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 RINSEcykl powtarzania - możliwości, jakie daje, gotosą 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 whilepę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 gotoJavaScript 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).
gotoprawdopodobnie jest niewykorzystany. To tworzy bardzo ładne wzorce obsługi błędów. Cholera, używamy switch, co jest gotow ogóle poza nazwą i nikt nie boli brzucha.
Nie. Nie uwzględnili tego w ECMAScript:
ECMAScript nie zawiera instrukcji goto.
gotoidealnie pasowałoby do koktajlu głupich "cech" javascript :)
gotojest jednak zastrzeżonym słowem kluczowym do użytku w przyszłości. Możemy tylko mieć nadzieję :)
gotoprzydał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. ...
}
}
breaki continuemogą być używane również w forpętlach. Ale tak naprawdę nie są one równoważne gotoz założeniem, że są zamknięte w strukturze powiązanej pętli (pętli), w porównaniu z gotoktó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.
continuew do ... whilepętli kontynuuje warunek sprawdzenia . W ten sposób gotoużycie wstecznego tutaj do ... while (0)nie działa. ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoopto 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 gotoMoż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 startjest 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 label3po 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 forpętlę? Powtarzaj tyle razy, ile chcesz. Lub whilepętla, powtarzaj, aż warunek zostanie spełniony. Istnieją struktury kontrolne, które pozwolą Ci powtórzyć kod. Pamiętam, że GOTOw 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 switchkonstrukcji, którą możesz zasymulować gotow 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 gotow 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;
}