如何在Javascript中使用goto?

时间:2012-03-17 15:28:09

标签: javascript goto

我有一些代码,我绝对必须使用goto来实现。例如,我想写一个这样的程序:

start:
alert("RINSE");
alert("LATHER");
repeat: goto start

有没有办法在Javascript中执行此操作?

15 个答案:

答案 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;
}