如何在 Javascript 中使用 goto?

IT技术 javascript goto
2021-01-13 09:26:54

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

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

有没有办法在 Javascript 中做到这一点?

6个回答

绝对地!有一个名为Summer of Goto的项目它可以让您充分发挥 JavaScript 的潜力,并将彻底改变您编写代码的方式。

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

[lbl] <label-name>
goto <label-name>

比如题中的例子可以写成这样:

[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;

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

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

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

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

这个预处理过程有一些限制,因为 while 循环不能跨越多个函数或块。不过,这没什么大不了的——我相信能够利用gotoJavaScript 的好处绝对会让你不知所措。

以上所有指向 goto.js 库的链接都已失效,这里是需要的链接:

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

Goto.js

PS 对于任何想知道的人(到目前为止总共是零人),Goto 之夏是由 Paul Irish 在讨论此脚本和 PHP 决定将 goto 添加到他们的语言中时普及的一个术语。

对于那些没有立即意识到整件事是一个笑话的人,请原谅我。<——(保险)。

+1 @AlexMills 。老实说,我认为goto可能没有得到充分利用。它产生了一些非常好的错误处理模式。oop,我们使用switchgoto除了名字之外,没有人会感到腹痛。
2021-03-21 09:26:54
@PeterOlson,但是 stackoverflow 旨在帮助人们学习编程。问题和答案应该有助于做到这一点。没有人因此得到帮助。
2021-03-30 09:26:54
@ShadowWizard 这个答案已经被大量免责声明所包围,人们在谈论为什么不应该使用它。让那些故意忽视这一点的人面临这样做的后果,我并不感到羞耻。
2021-04-04 09:26:54
@SurrealDreams 这可能是个玩笑,但它确实有效。您可以单击 jsFiddle 链接并查看它们是否确实有效。
2021-04-08 09:26:54
您链接到的文章实际上说明这是一个笑话:)
2021-04-11 09:26:54

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

ECMAScript 没有 goto 语句。

goto但是,是供将来使用的保留关键字。我们只能希望:)
2021-03-18 09:26:54
我想知道 GOTO 在调试 JavaScript 时是否有用。Afaik,只有 IE 在其调试器中提供 GOTO ......我实际上找到了它的用例,但我不确定它是否通常有用......在调试 JavaScript 时跳来跳去。你怎么认为?
2021-03-19 09:26:54
@Šime Vidas:我不确定使用 goto 功能进行调试是否有用。基本上,您会以一种在没有调试的情况下永远不会发生的方式来处理代码路径。
2021-04-06 09:26:54
真可惜……恕我直言goto,它非常适合 javascript 的愚蠢“功能”鸡尾酒:)
2021-04-07 09:26:54
goto当您想从嵌套函数返回时会很有用。例如,在使用 underscore.js 时,您在迭代数组时提供匿名函数。你不能从这样的函数内部返回,所以goto end;会很有用。
2021-04-09 09:26:54

在经典的 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 上运行。例如,我认为这就是他们让 Linux 内核在 JavaScript 中启动的方式。

笔记!这都是幼稚的解释。对于正确的字节码 Js 后端,还应考虑在输出代码之前检查循环。许多简单的 while 循环都可以被检测到,然后你可以使用循环而不是 goto。

不起作用。我必须let doLoop为此工作。和主循环:let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop) github.com/patarapolw/HanziLevelUp/blob/...
2021-03-23 09:26:54
continuedo ... while循环中继续检查条件因此,goto这里使用的向后do ... while (0)不起作用。ecma-international.org/ecma-262/5.1/#sec-12.6.1
2021-03-30 09:26:54

实际上,我看到 ECMAScript (JavaScript) 确实有一个 goto 语句。然而,JavaScript goto 有两种风格!

goto 的两种 JavaScript 风格称为标记为 continue 和标记为 break。JavaScript 中没有关键字“goto”。goto 是在 JavaScript 中使用 break 和 continue 关键字完成的。

这在http://www.w3schools.com/js/js_switch.asp的 w3schools 网站上或多或少有明确说明

我发现标记为 continue 和标记为 break 的文档表达得有些笨拙。

标记的 continue 和标记的 break 之间的区别在于它们的使用位置。标记为 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. ...
    }

}
“标记的 continue 只能在 while 循环中使用。” - 不,有标签breakcontinue也可以在for循环中使用但它们实际上并不等同于goto它们被锁定在相关循环的结构中,相比之下goto,当然可以 - 在拥有它的语言中 - 去任何地方。
2021-03-16 09:26:54

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

Agoto可以被认为是没有参数的尾调用。

这个例子:

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

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

 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 之类的宏系统来完成。

明确标记的尾部调用可能会让每个人都高兴。
2021-03-13 09:26:54
我相信 Safari 支持正确的尾调用。在给出答案时,可以通过命令行开关在 Chrome 中启用正确的尾调用。让我们希望他们重新考虑 - 或者至少开始支持明确标记的尾调用。
2021-04-09 09:26:54
“在 ES6 中实现支持正确的尾调用是可能的”。所有主要浏览器都禁用了 AFAIK 尾调用。
2021-04-12 09:26:54