Ich habe einen Code, den ich unbedingt implementieren muss goto
. Zum Beispiel möchte ich ein Programm wie dieses schreiben:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Gibt es eine Möglichkeit, dies in Javascript zu tun?
Ich habe einen Code, den ich unbedingt implementieren muss goto
. Zum Beispiel möchte ich ein Programm wie dieses schreiben:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Gibt es eine Möglichkeit, dies in Javascript zu tun?
Antworten:
Absolut! Es gibt ein Projekt namens Summer of Goto , mit dem Sie JavaScript in vollem Umfang nutzen und die Art und Weise, wie Sie Ihren Code schreiben können, revolutionieren können.
Mit diesem JavaScript-Vorverarbeitungstool können Sie eine Beschriftung erstellen und diese dann mithilfe der folgenden Syntax aufrufen:
[lbl] <label-name>
goto <label-name>
Das Beispiel in der Frage kann beispielsweise wie folgt geschrieben werden:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Beachten Sie, dass Sie sich nicht nur auf einfache triviale Programme wie einen endlosen LATHER
RINSE
Wiederholungszyklus beschränken - die Möglichkeiten goto
sind endlos und Sie können sogar Hello, world!
538 Mal eine Nachricht an die JavaScript-Konsole senden, wie folgt:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
Sie können mehr darüber lesen, wie goto implementiert wird , aber im Grunde führt es eine JavaScript-Vorverarbeitung durch, die die Tatsache ausnutzt, dass Sie ein goto mit einer beschrifteten while
Schleife simulieren können . Also, wenn Sie die "Hallo Welt!" Programm oben, es wird in so etwas übersetzt:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
Dieser Vorverarbeitungsprozess unterliegt einigen Einschränkungen, da sich while-Schleifen nicht über mehrere Funktionen oder Blöcke erstrecken können. Das ist jedoch keine große Sache - ich bin sicher, dass die Vorteile, goto
JavaScript nutzen zu können, Sie absolut überwältigen werden.
Alle oben genannten Links, die zur goto.js-Bibliothek führen, sind ALL DEAD. Hier werden Links benötigt:
goto.js (unkomprimiert) --- parseScripts.js (unkomprimiert)
Von Goto.js :
PS Für alle, die sich fragen (bisher insgesamt null Personen), ist Summer of Goto ein Begriff, der von Paul Irish populär gemacht wurde, während er dieses Skript und die Entscheidung von PHP diskutierte, goto in ihre Sprache aufzunehmen.
Und für diejenigen, die nicht sofort erkennen, dass diese ganze Sache ein Witz ist, bitte vergib mir. <- (Versicherung).
goto
es wahrscheinlich nicht ausreichend genutzt wird. Dies führt zu einigen sehr schönen Fehlerbehandlungsmustern. Heck, wir verwenden switch
, was goto
in allen außer Namen ist, und niemand Bauchschmerzen.
Nein, sie haben das nicht in ECMAScript aufgenommen:
ECMAScript hat keine goto-Anweisung.
goto
würde einfach perfekt in Javascript Cocktail von dummen "Features" passen :)
goto
ist jedoch ein reserviertes Schlüsselwort für die zukünftige Verwendung. Wir können nur hoffen :)
goto
wäre nützlich, wenn Sie von einer verschachtelten Funktion zurückkehren möchten. Wenn Sie beispielsweise underscore.js verwenden, stellen Sie eine anonyme Funktion bereit, wenn Sie über Arrays iterieren. Sie können innerhalb einer solchen Funktion nicht zurückkehren, dies goto end;
wäre also nützlich.
Eigentlich sehe ich, dass ECMAScript (JavaScript) DOES INDEED eine goto-Anweisung hat. Das JavaScript goto hat jedoch zwei Varianten!
Die beiden JavaScript-Varianten von goto heißen "continue" und "break". In JavaScript gibt es kein Schlüsselwort "goto". Das Goto wird in JavaScript mit den Schlüsselwörtern break und continue ausgeführt.
Und dies wird mehr oder weniger explizit auf der Website von w3schools hier http://www.w3schools.com/js/js_switch.asp angegeben .
Ich finde die Dokumentation der beschrifteten Fortsetzung und beschrifteten Pause etwas umständlich ausgedrückt.
Der Unterschied zwischen der beschrifteten Fortsetzung und der beschrifteten Unterbrechung besteht darin, wo sie verwendet werden können. Das beschriftete Fortsetzen kann nur innerhalb einer while-Schleife verwendet werden. Weitere Informationen finden Sie unter w3schools.
===========
Ein anderer Ansatz, der funktionieren wird, besteht darin, eine riesige while-Anweisung mit einer riesigen switch-Anweisung zu haben:
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
und continue
kann auch in for
Schleifen verwendet werden. Aber sie sind wirklich nicht gleichbedeutend damit goto
, dass sie in der Struktur der zugehörigen Schleife (n) eingeschlossen sind, im Vergleich dazu goto
können sie natürlich - in Sprachen, in denen sie vorhanden sind - überall hingehen.
In klassischem JavaScript müssen Sie do-while-Schleifen verwenden, um diesen Codetyp zu erreichen. Ich nehme an, Sie generieren möglicherweise Code für eine andere Sache.
Die Art und Weise, dies zu tun, wie beim Backend von Bytecode in JavaScript, besteht darin, jedes Beschriftungsziel in eine "beschriftete" Aufgabe zu verpacken.
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);
Jede beschriftete Do-While-Schleife, die Sie so verwenden, erstellt tatsächlich die beiden Beschriftungspunkte für die eine Beschriftung. Eine oben und eine am Ende der Schleife. Das Zurückspringen nutzt weiter und das Vorwärtsspringen benutzt Pause.
// 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)
Leider gibt es keinen anderen Weg, dies zu tun.
Normaler Beispielcode:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
Angenommen, der Code wird in Bytecodes codiert. Jetzt müssen Sie die Bytecodes in JavaScript einfügen, um Ihr Backend für einen bestimmten Zweck zu simulieren.
JavaScript-Stil:
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)
Die Verwendung dieser Technik macht den Job also für einfache Zwecke gut. Davon abgesehen können Sie nicht viel anderes tun.
Für normales Javacript sollten Sie goto nie verwenden müssen, daher sollten Sie diese Technik hier wahrscheinlich vermeiden, es sei denn, Sie übersetzen speziell anderen Stilcode, der unter JavaScript ausgeführt werden soll. Ich gehe davon aus, dass der Linux-Kernel auf diese Weise beispielsweise in JavaScript gestartet wird.
HINWEIS! Das ist alles eine naive Erklärung. Für ein korrektes Js-Backend von Bytecodes sollten Sie auch die Schleifen untersuchen, bevor Sie den Code ausgeben. Viele einfache while-Schleifen können als solche erkannt werden, und dann können Sie lieber Schleifen anstelle von goto verwenden.
continue
in einer do ... while
Schleife fährt mit der Prüfbedingung fort . Die Rückwärtsnutzung goto
hier do ... while (0)
funktioniert also nicht. ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoop
damit das funktioniert. Und Hauptschleife: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop)
github.com/patarapolw/HanziLevelUp/blob/…
Dies ist eine alte Frage, aber da JavaScript ein sich bewegendes Ziel ist, ist es in ES6 bei der Implementierung möglich, dass ordnungsgemäße Tail-Aufrufe unterstützt werden. Bei Implementierungen mit Unterstützung für ordnungsgemäße Tail-Aufrufe können Sie eine unbegrenzte Anzahl aktiver Tail-Aufrufe haben (dh Tail-Aufrufe vergrößern den Stapel nicht).
A goto
kann als Tail Call ohne Parameter betrachtet werden.
Das Beispiel:
start: alert("RINSE");
alert("LATHER");
goto start
kann geschrieben werden als
function start() { alert("RINSE");
alert("LATHER");
return start() }
Hier befindet sich der Aufruf von start
in der Endposition, sodass keine Stapelüberläufe auftreten.
Hier ist ein komplexeres Beispiel:
label1: A
B
if C goto label3
D
label3: E
goto label1
Zuerst teilen wir die Quelle in Blöcke auf. Jedes Etikett zeigt den Beginn eines neuen Blocks an.
Block1
label1: A
B
if C goto label3
D
Block2
label3: E
goto label1
Wir müssen die Blöcke mit gotos zusammenbinden. Im Beispiel folgt der Block E D, also fügen wir ein goto label3
nach D hinzu.
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
Jetzt wird jeder Block zu einer Funktion und jeder goto wird zu einem Tail Call.
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
Verwenden Sie zum Starten des Programms label1()
.
Das Umschreiben ist rein mechanisch und kann daher bei Bedarf mit einem Makrosystem wie sweet.js durchgeführt werden.
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;
}
Wie wäre es mit einer for
Schleife? Wiederholen Sie so oft Sie möchten. Oder while
wiederholen Sie eine Schleife, bis eine Bedingung erfüllt ist. Es gibt Kontrollstrukturen, mit denen Sie Code wiederholen können. Ich erinnere mich an GOTO
Basic ... es hat so einen schlechten Code gemacht! Moderne Programmiersprachen bieten Ihnen bessere Optionen, die Sie tatsächlich beibehalten können.
Es gibt eine Möglichkeit, dies zu tun, aber es muss sorgfältig geplant werden. Nehmen Sie zum Beispiel das folgende QBASIC-Programm:
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."
Erstellen Sie dann Ihr JavaScript, um zuerst alle Variablen zu initialisieren, gefolgt von einem ersten Funktionsaufruf, um den Ball ins Rollen zu bringen (wir führen diesen ersten Funktionsaufruf am Ende aus), und richten Sie Funktionen für jeden Satz von Zeilen ein, von denen Sie wissen, dass sie ausgeführt werden die eine Einheit.
Folgen Sie dem mit dem ersten Funktionsaufruf ...
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();
Das Ergebnis in diesem Fall ist:
a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
Im Allgemeinen würde ich GoTo wegen schlechter Lesbarkeit lieber nicht verwenden. Für mich ist es eine schlechte Ausrede, einfache iterative Funktionen zu programmieren, anstatt rekursive Funktionen programmieren zu müssen, oder noch besser (wenn Dinge wie ein Stapelüberlauf befürchtet werden), ihre wahren iterativen Alternativen (die manchmal komplex sein können).
So etwas würde reichen:
while(true) {
alert("RINSE");
alert("LATHER");
}
Genau dort gibt es eine Endlosschleife. Der Ausdruck ("true") in den Klammern der while-Klausel wird von der Javascript-Engine überprüft - und wenn der Ausdruck true ist, wird die Schleife weiter ausgeführt. Das Schreiben von "wahr" hier wird immer als wahr ausgewertet, daher eine Endlosschleife.
Sicher, mit dem switch
Konstrukt können Sie goto
in JavaScript simulieren . Leider bietet die Sprache keine goto
, aber dies ist ein guter Ersatz.
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
}
}
Sie sollten wahrscheinlich einige JS - Tutorials wie diese lesen ein .
Ich bin mir nicht sicher, ob goto
es überhaupt in JS existiert, aber in beiden Fällen fördert es einen schlechten Codierungsstil und sollte vermieden werden.
Du könntest es tun:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
Sie können einfach eine Funktion verwenden:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
Um eine goto-ähnliche Funktionalität zu erreichen und gleichzeitig den Aufrufstapel sauber zu halten, verwende ich diese Methode:
// 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();
}
// ...
Bitte beachten Sie, dass dieser Code langsam ist, da die Funktionsaufrufe der Timeout-Warteschlange hinzugefügt werden, die später in der Aktualisierungsschleife des Browsers ausgewertet wird.
Bitte beachten Sie auch, dass Sie Argumente übergeben können ( setTimeout(func, 0, arg1, args...)
in einem Browser, der neuer als IE9 ist, oder setTimeout(function(){func(arg1, args...)}, 0)
in älteren Browsern.
AFAIK, Sie sollten niemals auf einen Fall stoßen, der diese Methode erfordert, es sei denn, Sie müssen eine nicht parallele Schleife in einer Umgebung ohne asynchrone / wartende Unterstützung anhalten.
gehe zu Beginn und Ende aller Schließungen der Eltern
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);
}
}
Eine andere alternative Möglichkeit, dies zu erreichen, ist die Verwendung der Tail Calls. Aber so etwas haben wir in JavaScript nicht. Im Allgemeinen wird das Goto in JS mit den folgenden beiden Schlüsselwörtern ausgeführt. brechen und fortfahren , Referenz: Gehe zu Anweisung in JavaScript
Hier ist ein Beispiel:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}