goto
を使用して絶対に実装しなければならないコードがいくつかあります。たとえば、次のようなプログラムを作成します。
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Javascriptでそれを行う方法はありますか?
ECMAScriptにはgotoステートメントはありません。
実際、ECMAScript(JavaScript)には実際にgotoステートメントがあります。ただし、JavaScript gotoには2つのフレーバーがあります!
Gotoの2つのJavaScriptフレーバーは、ラベル付きcontinueおよびラベル付きbreakと呼ばれます。 JavaScriptには「goto」というキーワードはありません。 gotoは、breakキーワードとcontinueキーワードを使用してJavaScriptで実行されます。
そして、これは多かれ少なかれここのw3schoolsウェブサイトで明示的に述べられています http://www.w3schools.com/js/js_switch.asp 。
ラベル付きcontinueおよびラベル付きbreakのドキュメントがややぎこちなく表現されています。
ラベル付きcontinueとラベル付きbreakの違いは、それらが使用される場所です。ラベル付きcontinueは、whileループ内でのみ使用できます。詳細については、w3schoolsを参照してください。
===========
動作する別のアプローチは、内部に巨大なswitchステートメントを含む巨大なwhileステートメントを持つことです。
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. ...
}
}
従来のJavaScriptでは、do-whileループを使用してこのタイプのコードを実現する必要があります。おそらく他の何かのためにコードを生成していると思います。
JavaScriptへのバックエンドバイトコードのように、これを行う方法は、すべてのラベルターゲットを「ラベル付き」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);
このように使用するすべてのラベル付きdo-whileループは、実際には1つのラベルに対して2つのラベルポイントを作成します。 1つはループの一番上に、もう1つはループの最後にあります。後ろにジャンプするにはcontinueを使用し、前にジャンプするにはbreakを使用します。
// 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)
残念ながら、他の方法はありません。
通常のサンプルコード:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
したがって、コードはバイトコードにエンコードされるので、バイトコードをJavaScriptに入れて、何らかの目的でバックエンドをシミュレートする必要があります。
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)
そのため、この手法を使用すると、単純な目的のためにうまく機能します。それ以外は、あなたができることはそれほど多くありません。
通常のJavacriptの場合、gotoを使用する必要はないので、他のスタイルコードをJavaScriptで実行するように明確に変換する場合を除き、ここではおそらくこの手法を避ける必要があります。それが、LinuxカーネルをJavaScriptで起動する方法だと思います。
注意!これはすべて素朴な説明です。バイトコードの適切なJsバックエンドについては、コードを出力する前にループを調べることも検討してください。多くの単純なwhileループをそのように検出できるため、gotoの代わりにループを使用できます。
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;
}
これは古い質問ですが、JavaScriptは動くターゲットなので、ES6では適切なテールコールをサポートする実装が可能です。適切なテールコールをサポートする実装では、アクティブなテールコールの数に制限はありません(つまり、テールコールは「スタックを成長させません」)。
goto
は、パラメーターのない末尾呼び出しと考えることができます。
例:
start: alert("RINSE");
alert("LATHER");
goto start
として書くことができます
function start() { alert("RINSE");
alert("LATHER");
return start() }
ここでstart
の呼び出しは末尾位置にあるため、スタックオーバーフローは発生しません。
より複雑な例を次に示します。
label1: A
B
if C goto label3
D
label3: E
goto label1
まず、ソースをブロックに分割します。各ラベルは、新しいブロックの開始を示します。
Block1
label1: A
B
if C goto label3
D
Block2
label3: E
goto label1
Gotosを使用してブロックをバインドする必要があります。この例では、ブロックEはDの後に続くため、Dの後にgoto label3
を追加します。
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
これで、各ブロックが関数になり、各gotoが末尾呼び出しになります。
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
プログラムを開始するには、label1()
を使用します。
書き換えは純粋に機械的なものであるため、必要に応じてsweet.jsなどのマクロシステムで行うことができます。
for
ループはどうですか?好きなだけ繰り返します。または、while
ループ、条件が満たされるまで繰り返します。コードを繰り返すことができる制御構造があります。 BasicのGOTO
を覚えています...それはそのような悪いコードを作りました!最新のプログラミング言語では、実際に保守できるより優れたオプションが提供されます。
これを行う方法はありますが、慎重に計画する必要があります。たとえば、次の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."
次に、最初にすべての変数を初期化するJavaScriptを作成してから、ボールローリングを開始する初期関数呼び出しを行い(この初期関数呼び出しを最後に実行します)、実行されることがわかっているすべての行セットに対して関数を設定します1つのユニット。
最初の関数呼び出しでこれに従ってください...
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();
このインスタンスの結果は次のとおりです。
a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
おそらく、このようなJSチュートリアルを読む必要がありますone。
goto
がJSに存在するかどうかはわかりませんが、いずれにしても、コーディングスタイルが悪いので、避けるべきです。
できること:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
一般的に、読みやすさの観点からGoToを使用しない方がよいでしょう。私にとっては、再帰関数をプログラミングするのではなく、単純な反復関数をプログラミングするのは悪い言い訳です。さらに良いのは(スタックオーバーフローのようなものが恐れられる場合)、真の反復選択肢(複雑な場合もあります)です。
次のようなことができます:
while(true) {
alert("RINSE");
alert("LATHER");
}
その右には無限ループがあります。 while句のパラメーター内の式( "true")は、Javascriptエンジンがチェックするものです-そして、式がtrueの場合、ループを実行し続けます。ここに「true」と記述すると、常にtrueと評価されるため、無限ループになります。
もちろん、switch
構文を使用すると、JavaScriptでgoto
をシミュレートできます。残念ながら、この言語はgoto
を提供していませんが、これは十分な代替品です。
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
}
}
関数を簡単に使用できます:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
すべての親の閉鎖の開始と終了
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);
呼び出しスタックをクリーンに保ちながらgotoのような機能を実現するには、次のメソッドを使用しています。
// 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();
}
// ...
関数呼び出しがタイムアウトキューに追加され、ブラウザの更新ループで後で評価されるため、このコードは遅いことに注意してください。
また、引数を渡すことができることに注意してください(IE9よりも新しいブラウザーではsetTimeout(func, 0, arg1, args...)
を使用し、古いブラウザーではsetTimeout(function(){func(arg1, args...)}, 0)
を使用します)。
知る限り、非同期/待機のサポートがない環境で非並列ループを一時停止する必要がない限り、このメソッドを必要とするケースに遭遇することはありません。
// 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);
}
}