Mam kod, który absolutnie muszę zaimplementować przy użyciu goto
. Na przykład chcę napisać taki program:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Czy można to zrobić w Javascript?
Mam kod, który absolutnie muszę zaimplementować przy użyciu goto
. Na przykład chcę napisać taki program:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Czy można to zrobić w Javascript?
Odpowiedzi:
Absolutnie! Istnieje projekt o nazwie Summer of Goto, który pozwala na wykorzystanie pełnego potencjału JavaScript i zrewolucjonizuje sposób pisania kodu.
To narzędzie do wstępnego przetwarzania JavaScript umożliwia utworzenie etykiety, a następnie przejście do niej przy użyciu następującej składni:
[lbl] <label-name>
goto <label-name>
Na przykład przykład w pytaniu można zapisać w następujący sposób:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Zwróć uwagę, że nie jesteś ograniczony tylko do prostych, trywialnych programów, takich jak niekończący się LATHER
RINSE
cykl powtarzania - możliwości, jakie daje, goto
są nieskończone i możesz nawet Hello, world!
wysłać wiadomość do konsoli JavaScript 538 razy, na przykład:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
Możesz przeczytać więcej o implementacji goto , ale zasadniczo wykonuje on pewne wstępne przetwarzanie JavaScript, które wykorzystuje fakt, że możesz symulować goto za pomocą oznaczonej while
pętli . Tak więc, pisząc „Hello, world!” program powyżej, zostanie przetłumaczony na coś takiego:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
Istnieją pewne ograniczenia tego procesu wstępnego przetwarzania, ponieważ pętle while nie mogą rozciągać się na wiele funkcji lub bloków. Nie jest to jednak wielka sprawa - jestem pewien, że korzyści płynące z możliwości korzystania z goto
JavaScript absolutnie cię przytłoczy.
Cały powyższy link prowadzący do biblioteki goto.js to ALL DEAD, tutaj potrzebne są linki:
goto.js (nieskompresowany) --- parseScripts.js (nieskompresowany)
Z Goto.js :
PS Dla każdego, kto się zastanawia (jak dotąd w sumie zero osób), Summer of Goto to termin spopularyzowany przez Paula Irisha podczas omawiania tego skryptu i decyzji PHP o dodaniu goto do ich języka.
A tym, którzy nie od razu rozpoznają, że cała ta sprawa to żart, proszę mi wybaczyć. <- (ubezpieczenie).
goto
prawdopodobnie jest niewykorzystany. To tworzy bardzo ładne wzorce obsługi błędów. Cholera, używamy switch
, co jest goto
w ogóle poza nazwą i nikt nie boli brzucha.
Nie. Nie uwzględnili tego w ECMAScript:
ECMAScript nie zawiera instrukcji goto.
goto
idealnie pasowałoby do koktajlu głupich "cech" javascript :)
goto
jest jednak zastrzeżonym słowem kluczowym do użytku w przyszłości. Możemy tylko mieć nadzieję :)
goto
przydałoby się, gdy chcesz powrócić z funkcji zagnieżdżonej. Na przykład, używając podkreślenia underscore.js, udostępniasz anonimową funkcję podczas iteracji po tablicach. Nie możesz wrócić z wnętrza takiej funkcji, więc goto end;
byłoby przydatne.
Właściwie widzę, że ECMAScript (JavaScript) CZY INDEED ma instrukcję goto. Jednak JavaScript goto ma dwa smaki!
Dwie odmiany goto w JavaScript są nazywane etykietami kontynuacji i przerwania. W JavaScript nie ma słowa kluczowego „goto”. Goto jest wykonywane w JavaScript przy użyciu słów kluczowych break i continue.
Jest to mniej więcej wyraźnie określone na stronie w3schools tutaj http://www.w3schools.com/js/js_switch.asp .
Uważam, że dokumentacja oznaczona jako kontynuacja i oznaczona jako przerwa jest nieco niezręcznie wyrażona.
Różnica między oznaczoną kontynuacją a oznaczoną przerwą polega na tym, gdzie można ich użyć. Oznaczony ciąg dalszy może być używany tylko w pętli while. Zobacz w3schools po więcej informacji.
===========
Innym podejściem, które zadziała, jest gigantyczne oświadczenie while z gigantycznym oświadczeniem przełącznika w środku:
while (true)
{
switch (goto_variable)
{
case 1:
// some code
goto_variable = 2
break;
case 2:
goto_variable = 5 // case in etc. below
break;
case 3:
goto_variable = 1
break;
etc. ...
}
}
break
i continue
mogą być używane również w for
pętlach. Ale tak naprawdę nie są one równoważne goto
z założeniem, że są zamknięte w strukturze powiązanej pętli (pętli), w porównaniu z goto
którą oczywiście - w językach, które ją mają - przenoszą się gdziekolwiek.
W klasycznym JavaScript do osiągnięcia tego typu kodu potrzebne są pętle do-while. Zakładam, że być może generujesz kod do czegoś innego.
Sposobem na zrobienie tego, podobnie jak przy zapisywaniu kodu bajtowego w JavaScript, jest umieszczenie każdego celu etykiety w „oznaczonym” do-while.
LABEL1: do {
x = x + 2;
...
// JUMP TO THE END OF THE DO-WHILE - A FORWARDS GOTO
if (x < 100) break LABEL1;
// JUMP TO THE START OF THE DO WHILE - A BACKWARDS GOTO...
if (x < 100) continue LABEL1;
} while(0);
Każda oznaczona pętla do-while, której używasz w ten sposób, w rzeczywistości tworzy dwa punkty etykiety dla jednej etykiety. Jeden na górze i jeden na końcu pętli. Skakanie do tyłu używa kontynuacji, a skok do przodu używa przerwy.
// NORMAL CODE
MYLOOP:
DoStuff();
x = x + 1;
if (x > 100) goto DONE_LOOP;
GOTO MYLOOP;
// JAVASCRIPT STYLE
MYLOOP: do {
DoStuff();
x = x + 1;
if (x > 100) break MYLOOP;
continue MYLOOP;// Not necessary since you can just put do {} while (1) but it illustrates
} while (0)
Niestety nie ma innej możliwości.
Normalny przykładowy kod:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
Powiedzmy, że kod zostaje zakodowany do kodu bajtowego, więc teraz musisz umieścić kody bajtowe w JavaScript, aby symulować swój backend w jakimś celu.
Styl JavaScript:
LOOP1: do {
if (x >= 10) break LOOP1;
if (!Ok) break LOOP1;
z = 0;
LOOP2: do {
if (z >= 10) break LOOP2;
if (!DoStuff()) {
Ok = FALSE;
break LOOP2;
}
z++;
} while (1);// Note While (1) I can just skip saying continue LOOP2!
x++;
continue LOOP1;// Again can skip this line and just say do {} while (1)
} while(0)
Więc użycie tej techniki działa dobrze w prostych celach. Poza tym niewiele więcej możesz zrobić.
W przypadku normalnego Javacript nie powinieneś używać goto ever, więc prawdopodobnie powinieneś unikać tej techniki tutaj, chyba że tłumaczysz konkretnie inny kod stylu, aby działał w JavaScript. Zakładam, że w ten sposób na przykład pobierają jądro Linuksa w JavaScript.
UWAGA! To wszystko jest naiwne wyjaśnienie. Aby uzyskać poprawne zaplecze kodu bajtowego w języku Js, należy również rozważyć sprawdzenie pętli przed wyprowadzeniem kodu. Wiele prostych pętli while można wykryć jako takich, a następnie możesz raczej użyć pętli zamiast goto.
continue
w do ... while
pętli kontynuuje warunek sprawdzenia . W ten sposób goto
użycie wstecznego tutaj do ... while (0)
nie działa. ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoop
to zadziałało. I główna pętla: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop)
github.com/patarapolw/HanziLevelUp/blob/ ...
To stare pytanie, ale skoro JavaScript jest ruchomym celem - w ES6 jest to możliwe w przypadku implementacji obsługującej właściwe wywołania ogonowe. W implementacjach z obsługą poprawnych wywołań ogonowych, możesz mieć nieograniczoną liczbę aktywnych wywołań ogonowych (tj. Wywołania ogonowe nie „powiększają stosu”).
ZA goto
Można traktować jako wezwanie ogonowej bez parametrów.
Przykład:
start: alert("RINSE");
alert("LATHER");
goto start
można zapisać jako
function start() { alert("RINSE");
alert("LATHER");
return start() }
Tutaj call do start
jest na pozycji taila, więc nie będzie przepełnienia stosu.
Oto bardziej złożony przykład:
label1: A
B
if C goto label3
D
label3: E
goto label1
Najpierw podzieliliśmy źródło na bloki. Każda etykieta wskazuje początek nowego bloku.
Block1
label1: A
B
if C goto label3
D
Block2
label3: E
goto label1
Musimy połączyć bloki razem za pomocą goto. W przykładzie blok E następuje po D, więc dodajemy a goto label3
po D.
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
Teraz każdy blok staje się funkcją, a każde goto staje się wywołaniem końcowym.
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
Aby uruchomić program, użyj label1()
.
Przepisanie jest czysto mechaniczne i można je w razie potrzeby wykonać za pomocą systemu makr, takiego jak sweet.js.
const
start = 0,
more = 1,
pass = 2,
loop = 3,
skip = 4,
done = 5;
var label = start;
while (true){
var goTo = null;
switch (label){
case start:
console.log('start');
case more:
console.log('more');
case pass:
console.log('pass');
case loop:
console.log('loop');
goTo = pass; break;
case skip:
console.log('skip');
case done:
console.log('done');
}
if (goTo == null) break;
label = goTo;
}
Co powiesz na for
pętlę? Powtarzaj tyle razy, ile chcesz. Lub while
pętla, powtarzaj, aż warunek zostanie spełniony. Istnieją struktury kontrolne, które pozwolą Ci powtórzyć kod. Pamiętam, że GOTO
w Basicu ... zrobił taki zły kod! Nowoczesne języki programowania zapewniają lepsze opcje, które możesz w rzeczywistości obsługiwać.
Można to zrobić, ale należy to starannie zaplanować. Weźmy na przykład następujący program QBASIC:
1 A = 1; B = 10;
10 print "A = ",A;
20 IF (A < B) THEN A = A + 1; GOTO 10
30 PRINT "That's the end."
Następnie utwórz JavaScript, aby najpierw zainicjować wszystkie zmienne, a następnie wykonaj początkowe wywołanie funkcji, aby rozpocząć przewijanie piłki (wykonujemy to początkowe wywołanie funkcji na końcu) i skonfiguruj funkcje dla każdego zestawu linii, o których wiesz, że zostaną wykonane w jedna jednostka.
Postępuj zgodnie z tym z początkowym wywołaniem funkcji ...
var a, b;
function fa(){
a = 1;
b = 10;
fb();
}
function fb(){
document.write("a = "+ a + "<br>");
fc();
}
function fc(){
if(a<b){
a++;
fb();
return;
}
else
{
document.write("That's the end.<br>");
}
}
fa();
Wynik w tym przypadku to:
a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
Generalnie wolałbym nie używać GoTo ze względu na słabą czytelność. Dla mnie jest to zła wymówka dla programowania prostych funkcji iteracyjnych zamiast konieczności programowania funkcji rekurencyjnych, a nawet lepiej (jeśli obawiamy się takich rzeczy jak przepełnienie stosu), ich prawdziwych iteracyjnych alternatyw (które czasami mogą być złożone).
Coś takiego zrobiłoby:
while(true) {
alert("RINSE");
alert("LATHER");
}
To właśnie jest nieskończona pętla. Wyrażenie („prawda”) w parantezach klauzuli while jest tym, co silnik JavaScript będzie sprawdzał - a jeśli wyrażenie jest prawdziwe, pętla będzie działać. Zapisanie tutaj „prawda” zawsze daje wartość „prawda”, stąd nieskończona pętla.
Jasne, używając switch
konstrukcji, którą możesz zasymulować goto
w JavaScript. Niestety język nie zapewnia goto
, ale jest to wystarczająca wymiana.
let counter = 10
function goto(newValue) {
counter = newValue
}
while (true) {
switch (counter) {
case 10: alert("RINSE")
case 20: alert("LATHER")
case 30: goto(10); break
}
}
Powinieneś przeczytać kilka tutoriali JS jak ten jeden .
Nie jestem pewien, czy goto
w ogóle istnieje w JS, ale tak czy inaczej, zachęca to do złego stylu kodowania i należy go unikać.
Mógłbyś:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
Możesz w prosty sposób użyć funkcji:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
Aby uzyskać funkcjonalność podobną do goto, zachowując czystość stosu wywołań, używam tej metody:
// in other languages:
// tag1:
// doSomething();
// tag2:
// doMoreThings();
// if (someCondition) goto tag1;
// if (otherCondition) goto tag2;
function tag1() {
doSomething();
setTimeout(tag2, 0); // optional, alternatively just tag2();
}
function tag2() {
doMoreThings();
if (someCondition) {
setTimeout(tag1, 0); // those 2 lines
return; // imitate goto
}
if (otherCondition) {
setTimeout(tag2, 0); // those 2 lines
return; // imitate goto
}
setTimeout(tag3, 0); // optional, alternatively just tag3();
}
// ...
Należy pamiętać, że ten kod działa wolno, ponieważ wywołania funkcji są dodawane do kolejki limitów czasu, która jest oceniana później, w pętli aktualizacji przeglądarki.
Pamiętaj również, że możesz przekazywać argumenty (używając setTimeout(func, 0, arg1, args...)
w przeglądarce nowszej niż IE9 lub setTimeout(function(){func(arg1, args...)}, 0)
w starszych przeglądarkach.
AFAIK, nigdy nie powinieneś natrafiać na przypadek, który wymaga tej metody, chyba że musisz wstrzymać nierównoległą pętlę w środowisku bez obsługi async / await.
zaczynam i kończą wszystkie zamknięcia rodziców
var foo=false;
var loop1=true;
LABEL1: do {var LABEL1GOTO=false;
console.log("here be 2 times");
if (foo==false){
foo=true;
LABEL1GOTO=true;continue LABEL1;// goto up
}else{
break LABEL1; //goto down
}
console.log("newer go here");
} while(LABEL1GOTO);
// example of goto in javascript:
var i, j;
loop_1:
for (i = 0; i < 3; i++) { //The first for statement is labeled "loop_1"
loop_2:
for (j = 0; j < 3; j++) { //The second for statement is labeled "loop_2"
if (i === 1 && j === 1) {
continue loop_1;
}
console.log('i = ' + i + ', j = ' + j);
}
}
Innym alternatywnym sposobem osiągnięcia tego samego jest użycie wywołań ogonowych. Ale nie mamy czegoś takiego w JavaScript. Ogólnie rzecz biorąc, goto jest wykonywane w JS przy użyciu poniższych dwóch słów kluczowych. przerwij i kontynuuj , odniesienie: Goto Statement w JavaScript
Oto przykład:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}