如何在Javascript中使用goto?

Pet*_*son 122 javascript goto

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

start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Run Code Online (Sandbox Code Playgroud)

有没有办法在Javascript中这样做?

Pet*_*son 149

绝对!有一个名为Summer of Goto的项目允许您充分利用JavaScript,并将彻底改变您编写代码的方式.

此JavaScript预处理工具允许您创建标签,然后使用以下语法转到它:

[lbl] <label-name>
goto <label-name>
Run Code Online (Sandbox Code Playgroud)

例如,问题中的示例可以写成如下:

[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Run Code Online (Sandbox Code Playgroud)

请注意,您不仅限于简单的简单程序,如无休止的LATHER RINSE重复循环 - 提供的可能性goto是无穷无尽的,您甚至可以Hello, world!向JavaScript控制台发送消息538次,如下所示:

var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
Run Code Online (Sandbox Code Playgroud)

您可以阅读有关如何实现goto的更多信息,但基本上,它会执行一些JavaScript预处理,利用您可以使用带标签的while循环模拟goto这一事实.所以,当你写下"Hello,world!" 上面的程序,它被翻译成这样的东西:

var i = 0;
start: while(true) {
  console.log("Hello, world!");
  i++;
  if(i < 538) continue start;
  break;
}
Run Code Online (Sandbox Code Playgroud)

此预处理过程存在一些限制,因为while循环不能跨多个函数或块进行扩展.但这并不是什么大问题 - 我确信能够利用gotoJavaScript的好处绝对会让你感到压力.

以上链接导致goto.js库是ALL DEAD,这里是需要的链接:

goto.js(未压缩) --- parseScripts.js(未压缩)

来自Goto.js:

PS对于任何想知道的人(到目前为止总共为零人),Goto是一个由Paul Irish推广的术语,同时讨论这个脚本和PHP决定将goto添加到他们的语言中.

对于那些没有立即认识到这一切都是个玩笑的人,请原谅我.< - (保险).

  • 你链接到的文章实际上说它是个笑话:) (20认同)
  • @SurrealDreams这可能是一个笑话,但它确实有效.您可以单击jsFiddle链接,看看它们确实有效. (10认同)
  • @PeterOlson,但stackoverflow旨在帮助人们学习编程.这些问题和答案应该对此有用.没有人得到这方面的帮助. (6认同)
  • @AlexMills +1.老实说,我认为`goto`可能未得到充分利用.它使一些非常好的错误处理模式.哎呀,我们使用`switch`,除了名字之外都是`goto`,没有肚子疼. (6认同)
  • @ShadowWizard这个答案已经被很多免责声明所包围,人们在谈论为什么不应该这样做.让那些故意忽视这一点的人面对这样做的后果,我感到羞耻. (5认同)
  • 彼得,人们[正在认真对待](http://stackoverflow.com/q/14335353/447356)并实际使用这个笑话.你能否因为热爱JavaScript和编程而删除这个和那个网站(假设它是你的网站)? (3认同)
  • @PeterOlson没有人关心它是否真的有效.关键是它实际上并没有用.它甚至不是javascript,它是预处理. (2认同)
  • @pimvdb我从来没有否认它是,我只是说它功能齐全.仅仅因为这是一个笑话并不意味着你不能使用它.;) (2认同)
  • 仍然应该在顶部放一个免责声明,即答案是个玩笑 (2认同)
  • @ 0x1mason,[转到比转换更好](/sf/answers/8337241/).比尔盖茨曾经观察到令人惊讶的是,编程多年来并没有变得更简单或更快.这样做的原因是早期的语言有goto,而更新的语言虽然有新功能,但缺乏简单性和goto."*Goto认为有害*"在此被认为是有害的. (2认同)
  • 如何在没有 goto 的情况下跳出嵌套循环? (2认同)

pim*_*vdb 111

不,他们没有在ECMAScript中包含它:

ECMAScript没有goto语句.

  • 真可惜......恕我直言'goto`非常适合javascript的愚蠢"功能"鸡尾酒:) (8认同)
  • @ŠimeVidas:我不确定使用goto功能进行调试是否有用.基本上你会以一种在没有调试的情况下永远不会发生的方式来处理代码路径. (3认同)
  • 但是,`goto`是一个保留的关键字,供将来使用.我们只能希望:) (3认同)
  • 当你想从嵌套函数返回时,`goto`会很有用.例如,使用underscore.js时,在迭代数组时提供匿名函数.你不能从这样的函数里面返回,所以`goto end;`会很有用. (3认同)

小智 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.

===========

另一种方法是使用一个巨大的while语句,里面有一个巨大的switch语句:

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. ...
    }

}
Run Code Online (Sandbox Code Playgroud)

  • _"标记的continue只能在while循环中使用."_ - 不,标记为`break`和`continue`也可以在`for`循环中使用.但是它们真的_不等同于'goto`,因为它们被锁定在相关循环的结构中,与`goto`相比,当然可以 - 在拥有它的语言中 - 去任何地方. (8认同)

小智 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);
Run Code Online (Sandbox Code Playgroud)

您使用的每个标记的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)
Run Code Online (Sandbox Code Playgroud)

不幸的是,没有其他办法可以做到这一点.

正常示例代码:

while (x < 10 && Ok) {
  z = 0;
  while (z < 10) {
    if (!DoStuff()) {
      Ok = FALSE;
      break;
    }
    z++;
  }
  x++;
} 
Run Code Online (Sandbox Code Playgroud)

所以说代码被编码为字节码所以现在你必须将字节码放入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)
Run Code Online (Sandbox Code Playgroud)

因此,使用这种技术可以很好地完成工作.除此之外,你可以做的事情不多.

对于普通的Javacript,你不需要使用goto,所以你应该在这里避免使用这种技术,除非你特意翻译其他样式代码以在JavaScript上运行.我认为这就是他们如何在JavaScript中启动Linux内核的例子.

注意!这都是天真的解释.对于正确的Js字节码后端,还要考虑在输出代码之前检查循环.可以检测到许多简单的while循环,然后您可以使用循环而不是goto.

  • “do ... while”循环中的“继续”继续*到检查条件*。因此,这里使用“do ... while (0)”的向后“goto”不起作用。http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.1 (3认同)
  • +1喜欢没有条件的想法 (2认同)
  • 不起作用。我必须“let doLoop”才能使其工作。主循环:`let doLoop = false; do { if(条件){ doLoop = true; 继续; while (doLoop)` https://github.com/patarapolw/HanziLevelUp/blob/83eb0e3539a247a5cfc69d243e6a6e5ef373eda5/webapp/static/js/common.js#L90 (2认同)

Hen*_*est 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;
}
Run Code Online (Sandbox Code Playgroud)


soe*_*ard 12

这是一个老问题,但由于JavaScript是一个移动目标 - 在ES6上可以实现支持正确的尾调用.在支持正确尾调用的实现上,您可以拥有无​​限数量的活动尾调用(即尾调用不会"增加堆栈").

A goto可以被认为是没有参数的尾调用.

这个例子:

start: alert("RINSE");
       alert("LATHER");
       goto start
Run Code Online (Sandbox Code Playgroud)

可写成

 function start() { alert("RINSE");
                    alert("LATHER");
                    return start() }
Run Code Online (Sandbox Code Playgroud)

这里的调用start位于尾部位置,因此不会有堆栈溢出.

这是一个更复杂的例子:

 label1:   A
           B
           if C goto label3
           D
 label3:   E
           goto label1
Run Code Online (Sandbox Code Playgroud)

首先,我们将源分成块.每个标签表示新块的开始.

 Block1
     label1:   A
               B
               if C goto label3
               D

  Block2    
     label3:   E
               goto label1
Run Code Online (Sandbox Code Playgroud)

我们需要使用gotos将块绑定在一起.在示例中,块E跟随D,因此我们goto label3在D之后添加一个.

 Block1
     label1:   A
               B
               if C goto label2
               D
               goto label2

  Block2    
     label2:   E
               goto label1
Run Code Online (Sandbox Code Playgroud)

现在每个块都成为一个函数,每个goto变成一个尾调用.

 function label1() {
               A
               B
               if C then return( label2() )
               D
               return( label2() )
 }

 function label2() {
               E
               return( label1() )
 }
Run Code Online (Sandbox Code Playgroud)

要启动该程序,请使用label1().

重写纯粹是机械的,因此可以使用宏系统,如sweet.js,如果需要的话.

  • 明确标记的尾部调用可能会让每个人都高兴。 (2认同)

Sur*_*ams 8

怎么样一个for循环?根据需要重复多次.或while循环,重复直到满足条件.有控制结构可以让你重复代码.我记得GOTO在Basic ...它编写了这么糟糕的代码!现代编程语言为您提供了实际可以维护的更好选择.


Eli*_*zio 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."
Run Code Online (Sandbox Code Playgroud)

然后创建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();
Run Code Online (Sandbox Code Playgroud)

这个例子的结果是:

a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
Run Code Online (Sandbox Code Playgroud)


Mat*_*zen 6

一般来说,我不喜欢使用GoTo来提高可读性.对我来说,这是编写简单迭代函数的一个不好的借口,而不是编写递归函数,甚至更好(如果担心Stack Overflow之类的东西),它们真正的迭代替代方案(有时可能很复杂).

这样的事情会做:

while(true) {
   alert("RINSE");
   alert("LATHER");
}
Run Code Online (Sandbox Code Playgroud)

那就是无限循环.while子句的parantheses中的表达式("true")是Javascript引擎将检查的 - 如果表达式为true,它将保持循环运行.在这里写"true"总是评估为true,因此是无限循环.


Kon*_*ski 6

当然,使用该switch构造您可以goto在JavaScript中进行仿真。不幸的是,该语言没有提供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
  }
}
Run Code Online (Sandbox Code Playgroud)


Jov*_*vic 5

你或许应该阅读一些JS教程这样的一个.

不确定是否goto存在于JS中,但无论如何,它都会鼓励编码风格错误,应该避免使用.

你可以这样做:

while ( some_condition ){
    alert('RINSE');
    alert('LATHER');
}
Run Code Online (Sandbox Code Playgroud)