Tengo un código que absolutamente debo implementar usando goto
. Por ejemplo, quiero escribir un programa como este:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
¿Hay alguna manera de hacer eso en Javascript?
Tengo un código que absolutamente debo implementar usando goto
. Por ejemplo, quiero escribir un programa como este:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
¿Hay alguna manera de hacer eso en Javascript?
Respuestas:
¡Absolutamente! Hay un proyecto llamado Summer of Goto que le permite usar JavaScript en todo su potencial y revolucionará la forma en que puede escribir su código.
Esta herramienta de preprocesamiento de JavaScript le 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;
Tenga en cuenta que no solo se limita a programas triviales simples como un LATHER
RINSE
ciclo de repetición sin fin : las posibilidades que ofrece goto
son infinitas e incluso puede enviar un Hello, world!
mensaje a la consola de JavaScript 538 veces, de esta manera:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
Puede leer más sobre cómo se implementa goto , pero básicamente realiza un preprocesamiento de JavaScript que aprovecha el hecho de que puede simular un goto con un bucle etiquetadowhile
. Entonces, cuando escribes el "¡Hola, mundo!" programa anterior, se traduce a algo como esto:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
Existen algunas limitaciones para 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
JavaScript lo abrumarán por completo.
Todo el enlace anterior que conduce a la biblioteca goto.js está MUERTO, aquí hay enlaces necesarios:
goto.js (sin comprimir) --- parseScripts.js (sin comprimir)
De Goto.js :
PD: Para cualquiera que se pregunte (hasta ahora un total de cero personas), Summer of Goto es un término que fue popularizado por Paul Irish, mientras habla sobre este script y la decisión de PHP de agregar goto a su idioma.
Y para aquellos que no reconocen de inmediato que todo esto es una broma, perdónenme. <- (seguro).
goto
probablemente está subutilizado. Hace algunos patrones de manejo de errores muy agradables. Diablos, usamos switch
, que está goto
en todo menos en el nombre, y a nadie le duele el vientre.
No. No incluyeron eso en ECMAScript:
ECMAScript no tiene declaración goto.
goto
encajaría perfectamente en el cóctel de "características" estúpidas de JavaScript :)
goto
Sin embargo, es una palabra clave reservada para uso futuro. Solo podemos esperar :)
goto
sería útil cuando desee regresar de una función anidada. Por ejemplo, cuando usa underscore.js, proporciona una función anónima al iterar sobre matrices. No puede regresar desde dentro de una función así, por goto end;
lo que sería útil.
En realidad, veo que ECMAScript (JavaScript) TIENE DE VERDAD una declaración goto. ¡Sin embargo, el goto de JavaScript tiene dos sabores!
Los dos sabores de JavaScript de goto se denominan etiquetado continuar y rotulado rotura. No hay una palabra clave "goto" en JavaScript. El goto se realiza en JavaScript utilizando las palabras clave break y continue.
Y esto se afirma más o menos explícitamente en el sitio web de w3schools aquí http://www.w3schools.com/js/js_switch.asp .
Encuentro la documentación de la etiqueta continuar y rotura rotulada algo torpemente expresada.
La diferencia entre el continuado etiquetado y el descanso rotulado es dónde se pueden usar. La etiqueta continuar solo puede usarse dentro de un ciclo while. Vea w3schools para más información.
===========
Otro enfoque que funcionará es tener una declaración gigante mientras que con una declaración de interruptor gigante 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. ...
}
}
break
y también continue
puede usarse en for
bucles. Pero en realidad no son equivalentes, goto
dado que están encerrados en la estructura de los bucles relacionados, en comparación con los goto
que, por supuesto, pueden ir a cualquier lugar, en los idiomas que lo tienen.
En JavaScript clásico, debe usar bucles do-while para lograr este tipo de código. Supongo que tal vez estás generando código para otra cosa.
La forma de hacerlo, como para el código de bytes de backending a JavaScript, es envolver cada objetivo de etiqueta en un tiempo "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 etiquetado que usa de esta manera crea los dos puntos de etiqueta para una etiqueta. Uno en la parte superior y otro al final del bucle. Saltar hacia atrás usa continuar y saltar hacia adelante usa descanso.
// 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)
Lamentablemente, no hay otra forma de hacerlo.
Código de ejemplo normal:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
Digamos que el código se codifica en bytecodes, por lo que ahora debe poner los bytecodes en JavaScript para simular su backend para algún propósito.
Estilo 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)
Por lo tanto, usar esta técnica hace el trabajo bien para propósitos simples. Aparte de eso, no hay mucho más que puedas hacer.
Para Javacript normal, no debería necesitar usar goto nunca, por lo que probablemente debería evitar esta técnica aquí a menos que esté traduciendo específicamente otro código de estilo para ejecutar en JavaScript. Supongo que así es como hacen que el kernel de Linux arranque en JavaScript, por ejemplo.
¡NOTA! Esta es toda una explicación ingenua. Para el backend Js apropiado de los códigos de bytes, también considere examinar los bucles antes de generar el código. Muchos bucles while simples se pueden detectar como tales y luego puede usar bucles en lugar de ir a.
continue
en un do ... while
bucle continúa a la condición de verificación . El uso al revés goto
aquí, por lo do ... while (0)
tanto, no funciona. ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoop
para que esto funcione. Y bucle principal: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop)
github.com/patarapolw/HanziLevelUp/blob/…
Esta es una pregunta antigua, pero dado que JavaScript es un objetivo móvil, es posible en ES6 en la implementación que admita llamadas de cola adecuadas. En implementaciones con soporte para llamadas de cola adecuadas, puede tener un número ilimitado de llamadas de cola activas (es decir, las llamadas de cola no "hacen crecer la pila").
UNA 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, entonces agregamos 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 cola.
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
Para iniciar el programa, use label1()
.
La reescritura es puramente mecánica y, por lo tanto, se puede hacer con un sistema macro como sweet.js si es necesario.
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;
}
¿Qué tal un for
bucle? Repite tantas veces como quieras. O un while
bucle, repita hasta que se cumpla una condición. Hay estructuras de control que le permitirán repetir el código. Recuerdo GOTO
en Basic ... ¡hizo un código tan malo! Los lenguajes de programación modernos le ofrecen mejores opciones que realmente puede mantener.
Hay una manera de hacerlo, pero debe planificarse con cuidado. Tomemos, por ejemplo, el siguiente programa 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."
Luego cree su JavaScript para inicializar todas las variables primero, seguido de una llamada de función inicial para comenzar a rodar la bola (ejecutamos esta llamada de función inicial al final), y configure funciones para cada conjunto de líneas que sabe que se ejecutarán en La unidad.
Siga esto con la llamada de función inicial ...
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();
El resultado en esta instancia es:
a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
En general, preferiría no usar GoTo por mala legibilidad. Para mí, es una mala excusa para programar funciones iterativas simples en lugar de tener que programar funciones recursivas, o incluso mejor (si se teme un desbordamiento de pila), sus verdaderas alternativas iterativas (que a veces pueden ser complejas).
Algo como esto haría:
while(true) {
alert("RINSE");
alert("LATHER");
}
Que justo allí hay un bucle infinito. La expresión ("verdadero") dentro de las paréntesis de la cláusula while es lo que verificará el motor Javascript, y si la expresión es verdadera, mantendrá el ciclo en ejecución. Escribir "verdadero" aquí siempre se evalúa como verdadero, por lo tanto, un bucle infinito.
Claro, usando la switch
construcción puedes simular goto
en JavaScript. Desafortunadamente, el idioma no proporciona goto
, pero este es un reemplazo lo 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
}
}
Probablemente debería leer algunos tutoriales JS como este uno .
No estoy seguro si goto
existe en JS, pero, de cualquier manera, alienta un estilo de codificación incorrecto y debe evitarse.
Podrías hacerlo:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
Simplemente puede usar una función:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
Para lograr una funcionalidad similar a goto mientras se mantiene limpia la pila de llamadas, estoy usando este método:
// 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();
}
// ...
Tenga en cuenta que este código es lento ya que las llamadas de función se agregan a la cola de tiempos de espera, que se evalúa más adelante, en el ciclo de actualización del navegador.
Tenga en cuenta también que puede pasar argumentos (utilizando un setTimeout(func, 0, arg1, args...)
navegador más nuevo que IE9, o setTimeout(function(){func(arg1, args...)}, 0)
en navegadores más antiguos.
AFAIK, nunca debería toparse con un caso que requiera este método a menos que necesite pausar un bucle no paralelo en un entorno sin soporte asíncrono / en espera.
ir al principio y al final de todos los cierres de padres
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);
// 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);
}
}
Otra forma alternativa de lograr lo mismo es utilizar las llamadas de cola. Pero no tenemos nada de eso en JavaScript. Entonces, generalmente, el goto se logra en JS usando las dos palabras clave a continuación. romper y continuar , referencia: Ir a la declaración en JavaScript
Aquí hay un ejemplo:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}