我有一些代码,我绝对必须使用goto
来实现。例如,我想写一个这样的程序:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
有没有办法在Javascript中执行此操作?
答案 0 :(得分:137)
绝对!有一个名为Summer of Goto的项目允许您充分利用JavaScript,并将彻底改变您编写代码的方式。
此JavaScript预处理工具允许您创建标签,然后使用以下语法转到它:
[lbl] <label-name>
goto <label-name>
例如,问题中的示例可以写成如下:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
请注意,您不仅限于简单的琐碎程序,例如无休止的LATHER
RINSE
重复循环 - goto
提供的可能性是无穷无尽的,您甚至可以制作{{1}消息到JavaScript控制台538次,如下所示:
Hello, world!
You can read more about how goto is implemented,但基本上,它会进行一些JavaScript预处理,利用您可以使用labelled while
loop模拟goto的事实。所以,当你写下“Hello,world!”上面的程序,它被翻译成这样的东西:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
此预处理过程存在一些限制,因为while循环无法跨多个函数或块进行扩展。但这不是什么大问题 - 我确信在JavaScript中利用var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
的好处绝对会让你无所适从。
导致goto.js库的所有上述链接都是DEAD,这里是需要的链接:
goto.js (uncompressed) --- parseScripts.js (uncompressed)
来自Goto.js:
P.S。对于任何想知道的人(到目前为止总共为零人),Goto的夏天是一个由Paul Irish推广的术语,同时讨论这个脚本和PHP决定将goto添加到他们的语言中。
对于那些没有立即认识到这一切都是个玩笑的人,请原谅我。 &LT ;-(保险)。
答案 1 :(得分:99)
没有。 They did not include that in ECMAScript:
ECMAScript没有goto声明。
答案 2 :(得分:32)
实际上,我看到ECMAScript(JavaScript)DOES INDEED有一个goto语句。但是,JavaScript goto有两种风格!
goto的两种JavaScript风格被称为标记为continue并标记为break。 JavaScript中没有关键字“goto”。 goto是使用break和continue关键字在JavaScript中完成的。
在w3schools网站http://www.w3schools.com/js/js_switch.asp或多或少地明确说明了这一点。
我发现标记为“继续”和“标记符”的文档有点笨拙地表达。
标记的中断和标记中断之间的区别在于它们可以被使用的位置。标记的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. ...
}
}
答案 3 :(得分:30)
在经典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循环实际上为一个标签创建了两个标签点。一个在顶部,一个在循环结束。跳回使用继续,跳跃使用休息。
// 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上运行。我认为这就是他们如何在JavaScript中启动Linux内核的例子。
请注意!这都是天真的解释。对于正确的Js字节码后端,还要考虑在输出代码之前检查循环。可以检测到许多简单的while循环,然后你可以使用循环而不是goto。
答案 4 :(得分:14)
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;
}
答案 5 :(得分:11)
这是一个老问题,但由于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,如果需要的话。
答案 6 :(得分:8)
for
循环怎么样?根据需要重复多次。或者while
循环,重复直到满足条件。有控制结构可以让你重复代码。我记得Basic中的GOTO
...它编写了这么糟糕的代码!现代编程语言为您提供了实际可以维护的更好选择。
答案 7 :(得分:7)
有一种方法可以做到,但需要仔细规划。 以下面的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来首先初始化所有变量,然后进行初始函数调用以开始滚动(我们在结束时执行这个初始函数调用),并为你知道的每一行设置函数在一个单元中执行。
按照初始函数调用...
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.
答案 8 :(得分:5)
你应该阅读一些像这样的 one 的JS教程。
不确定JS中是否存在goto
,但无论如何,它都会鼓励编码风格错误,应该避免使用。
你可以这样做:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
答案 9 :(得分:5)
一般来说,我不喜欢使用GoTo,因为它的可读性差。对我来说,这是编写简单迭代函数的一个不好的借口,而不是编写递归函数,甚至更好(如果担心Stack Overflow之类的东西),它们真正的迭代替代方案(有时可能很复杂)。
这样的事情可以做到:
while(true) {
alert("RINSE");
alert("LATHER");
}
那就是无限循环。 while子句的parantheses中的表达式(“true”)是Javascript引擎将检查的 - 如果表达式为true,它将保持循环运行。在这里写“真”总是评估为真,因此是无限循环。
答案 10 :(得分:4)
您可以简单地使用一个功能:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
答案 11 :(得分:3)
转到所有父母关闭的开始和结束
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);
答案 12 :(得分:3)
为了在保持调用堆栈清洁的同时实现类似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)
。
AFAIK,除非你需要在没有异步/等待支持的环境中暂停非可并行循环,否则你不应该遇到需要这种方法的情况。
答案 13 :(得分:1)
// 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);
}
}
答案 14 :(得分:-1)
另一种实现此目的的替代方法是使用tail调用。但是,JavaScript中没有类似的功能。 因此,通常,goto是使用以下两个关键字在JS中完成的。 休息,然后 继续, 参考:Goto Statement in JavaScript
这里是一个例子:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}