Answers:
绝对!有一个名为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
loop模拟goto的事实。因此,当您编写“你好,世界!”时 上面的程序,它被翻译成这样的东西:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
此预处理过程有一些限制,因为while循环无法跨越多个功能或块。不过,这没什么大不了的-我相信能够利用goto
JavaScript的好处绝对会让您不知所措。
上面所有通往goto.js库的链接都是DEAD DEAD,这是需要的链接:
goto.js(未压缩) - parseScripts.js(未压缩)
从Goto.js:
PS对于任何想知道的人(到目前为止共有零个人),Summer of Goto是Paul Irish推广的一个术语,同时讨论了该脚本以及PHP决定将goto添加到他们的语言中的决定。
对于那些没有立即意识到这整个事情是在开玩笑的人,请原谅我。<—(保险)。
goto
可能未得到充分利用。它提供了一些非常好的错误处理模式。哎呀,我们使用switch
,这goto
只是名字,没有人肚子疼。
ECMAScript没有goto语句。
goto
,完全可以很好地融入javascript的愚蠢“功能”鸡尾酒):)
goto
是保留的关键字,以备将来使用。我们只能希望:)
goto
当您想从嵌套函数返回时将很有用。例如,当使用underscore.js时,您可以在遍历数组时提供匿名函数。您不能从此类函数内部返回,因此goto end;
很有用。
实际上,我看到ECMAScript(JavaScript)确实具有goto语句。但是,JavaScript goto有两种风格!
goto的两种JavaScript风格分别称为标记为Continue和标记为break。JavaScript中没有关键字“ goto”。goto在JavaScript中使用break和continue关键字完成。
这在w3schools网站http://www.w3schools.com/js/js_switch.asp上或多或少地明确指出。
我发现标有“继续”和标有“ 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. ...
}
}
break
,continue
也可以for
循环使用。但是,它们实际上并不等同于goto
将它们锁定在相关循环的结构中,而与之相比goto
,当然可以(在拥有它的语言中)可以到达任何地方。
在经典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。
continue
在do ... while
循环中继续检查条件。因此,goto
此处向后使用do ... while (0)
无效。ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoop
为此工作。与主回路:let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop)
github.com/patarapolw/HanziLevelUp/blob/...
这是一个古老的问题,但是由于JavaScript是一个不断发展的目标-在ES6中有可能实现支持适当的尾部调用的实现。在支持适当的尾部调用的实现中,您可以有无限数量的活动尾部调用(即,尾部调用不会“增加堆栈”)。
goto
可以将A 视为没有参数的尾部调用。
这个例子:
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,因此我们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之类的宏系统来完成。
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;
}
有一种方法可以完成,但是需要仔细计划。以下面的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.
通常,我不希望使用GoTo来降低可读性。对我来说,对简单的迭代函数进行编程而不是对递归函数进行编程是一个不好的借口,或者甚至更好(如果担心像Stack Overflow这样的东西),它们是真正的迭代替代方案(有时可能很复杂)。
这样的事情会做:
while(true) {
alert("RINSE");
alert("LATHER");
}
那个权利存在无限循环。while子句的括号内的表达式(“ true”)是Javascript引擎将检查的内容-如果该表达式为true,它将保持循环运行。在这里写“ true”总是评估为true,因此是无限循环。
当然,使用该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
}
}
你或许应该阅读一些JS教程这样的一个。
完全不确定goto
JS 是否存在,但是,无论哪种方式,它都会导致不良的编码风格,应避免使用。
您可以这样做:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
为了在保持调用堆栈整洁的同时实现类似于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();
}
// ...
请注意,此代码很慢,因为函数调用已添加到超时队列中,稍后在浏览器的更新循环中对其进行评估。
另请注意,您可以传递参数(setTimeout(func, 0, arg1, args...)
在IE9或更高版本的浏览器中使用,或setTimeout(function(){func(arg1, args...)}, 0)
在较旧的浏览器中使用。
AFAIK,除非您需要在没有异步/等待支持的环境中暂停不可并行的循环,否则永远不要遇到需要这种方法的情况。
// 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);
}
}
实现此目的的另一种替代方法是使用尾部调用。但是,我们在JavaScript中没有类似的东西。因此,通常,goto是使用以下两个关键字在JS中完成的。 中断并 继续,参考:JavaScript中的Goto语句
这是一个例子:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}