¿Cómo puedo usar goto en Javascript?
Tengo un código que absolutamente debo implementar usando goto. Por ejemplo, quiero escribir un programa así:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
¿Hay una manera de hacer eso en Javascript?
Respuesta #1
¡Absolutamente! Hay un proyecto llamado Summer of Goto que te permite usar JavaScript en todo su potencial y revolucionará la forma en que puedes escribir tu código.
Esta herramienta de preprocesamiento de JavaScript te permite crear una etiqueta y luego ir a ella usando esta sintaxis:
[lbl] <label-name>
goto <label-name>
Por ejemplo, el ejemplo en la pregunta se puede escribir de la siguiente manera:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Ten en cuenta que no estás limitado solo a programas triviales simples como un ciclo interminable de LATHER RINSE—las posibilidades que ofrece goto son infinitas e incluso puedes hacer un mensaje de Hello, world! en la consola de JavaScript 538 veces, así:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
Puedes leer más sobre cómo se implementa goto, pero básicamente, hace un preprocesamiento de JavaScript que aprovecha el hecho de que puedes simular un goto con un bucle while etiquetado. Así que, cuando escribes el programa "¡Hola, mundo!" mencionado arriba, se traduce en algo como esto:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
Hay algunas limitaciones en este proceso de preprocesamiento, porque los bucles while no pueden extenderse a través de múltiples funciones o bloques. Sin embargo, eso no es un gran problema; estoy seguro de que los beneficios de poder aprovechar goto en JavaScript te abrumarán por completo.
Todos los enlaces anteriores que conducen a la biblioteca goto.js están TODOS CAÍDOS, aquí están los enlaces necesarios:
goto.js (sin comprimir) --- parseScripts.js (sin comprimir)
De Goto.js:
Respuesta #2
No. No incluyeron eso en ECMAScript:
ECMAScript no tiene la instrucción goto.
Respuesta #3
En el JavaScript clásico necesitas usar bucles do-while para lograr este tipo de código. Supongo que tal vez estás generando código para otra cosa.
La manera de hacerlo, como para generar bytecode en JavaScript, es envolver cada objetivo de etiqueta en un do-while "etiquetado".
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);
Cada bucle do-while con etiqueta que uses así en realidad crea dos puntos de etiqueta para una etiqueta. Uno en la parte superior y otro al final del bucle. Saltar hacia atrás usa continue y saltar hacia adelante usa break.
// 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)
Desafortunadamente, no hay otra manera de hacerlo.
Código de ejemplo normal:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
Entonces supongamos que el código se codifica en bytecodes, así que ahora debes poner los bytecodes en JavaScript para simular tu backend con algún propósito.
Estilo de 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)
Así que usar esta técnica hace bien el trabajo para fines simples. Fuera de eso, no hay mucho más que puedas hacer.
Para el JavaScript normal, no deberías necesitar usar goto nunca, por lo que probablemente deberías evitar esta técnica aquí a menos que estés traduciendo específicamente otro estilo de código para ejecutarlo en JavaScript. Supongo que así es como logran que el kernel de Linux arranque en JavaScript, por ejemplo.
¡NOTA! Esta es toda una explicación ingenua. Para un backend de bytecodes de Js adecuado, también considere examinar los bucles antes de generar el código. Muchos bucles simples while pueden detectarse como tales y luego puede usar bucles en lugar de goto.
Respuesta #4
De hecho, veo que ECMAScript (JavaScript) SÍ TIENE una instrucción goto. ¡Sin embargo, el goto de JavaScript tiene dos versiones!
Los dos tipos de goto en JavaScript se llaman continue con etiqueta y break con etiqueta. No existe la palabra clave "goto" en JavaScript. El goto se logra en JavaScript usando las palabras clave break y continue.
Y esto está más o menos explícitamente indicado en el sitio web de w3schools aquí http://www.w3schools.com/js/js_switch.asp.
Encuentro que la documentación del continue con etiqueta y del break con etiqueta está expresada de manera algo torpe.
La diferencia entre el continue etiquetado y el break etiquetado es dónde pueden ser usados. El continue etiquetado solo puede ser usado dentro de un bucle while. Consulta w3schools para obtener más información.
===========
Otro enfoque que funcionará es tener una gran declaración while con una gran declaración switch dentro:
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. ...
}
}
Respuesta #5
Esta es una pregunta antigua, pero dado que JavaScript es un objetivo en movimiento, es posible en ES6 en implementaciones que soportan llamadas de cola adecuadas. En implementaciones con soporte para llamadas de cola adecuadas, puedes tener un número ilimitado de llamadas de cola activas (es decir, las llamadas de cola no "aumentan la pila").
Un goto puede considerarse como una llamada de cola sin parámetros.
El ejemplo:
start: alert("RINSE");
alert("LATHER");
goto start
se puede escribir como
function start() { alert("RINSE");
alert("LATHER");
return start() }
Aquí la llamada a start está en posición de cola, por lo que no habrá desbordamientos de pila.
Aquí hay un ejemplo más complejo:
label1: A
B
if C goto label3
D
label3: E
goto label1
Primero, dividimos la fuente en bloques. Cada etiqueta indica el inicio de un nuevo bloque.
Block1
label1: A
B
if C goto label3
D
Block2
label3: E
goto label1
Necesitamos unir los bloques usando gotos. En el ejemplo, el bloque E sigue a D, por lo que añadimos un goto label3 después de D.
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
Ahora cada bloque se convierte en una función y cada goto se convierte en una llamada final.
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
Para iniciar el programa, usa label1().
La reescritura es puramente mecánica y, por lo tanto, se puede hacer con un sistema de macros como sweet.js si es necesario.
Respuesta #6
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;
}
Respuesta #7
Claro, usando la construcción switch puedes simular goto en JavaScript. Desafortunadamente, el lenguaje no ofrece un recurso de referencia, pero este es un reemplazo suficientemente bueno.
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
}
}
