Eu tenho algum código que eu absolutamente devo implementar usando goto
. Por exemplo, eu quero escrever um programa como este:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Existe uma maneira de fazer isso em Javascript?
Eu tenho algum código que eu absolutamente devo implementar usando goto
. Por exemplo, eu quero escrever um programa como este:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Existe uma maneira de fazer isso em Javascript?
Respostas:
Absolutamente! Existe um projeto chamado Summer of Goto que permite que você use JavaScript em todo o seu potencial e revolucionará a maneira como você pode escrever seu código.
Essa ferramenta de pré-processamento JavaScript permite criar um rótulo e, em seguida, saltar usando esta sintaxe:
[lbl] <label-name>
goto <label-name>
Por exemplo, o exemplo na pergunta pode ser escrito da seguinte maneira:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Observe que você não se limita apenas a programas triviais simples como um LATHER
RINSE
ciclo de repetição sem fim - as possibilidades oferecidas goto
são infinitas e você pode até Hello, world!
enviar uma mensagem para o console do JavaScript 538 vezes, assim:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
Você pode ler mais sobre como o goto é implementado , mas basicamente ele realiza algum pré-processamento de JavaScript que aproveita o fato de que você pode simular um goto com um loop rotuladowhile
. Então, quando você escreve o "Olá, mundo!" programa acima, ele é traduzido para algo como isto:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
Existem algumas limitações nesse processo de pré-processamento, porque os loops while não podem se estender por várias funções ou blocos. Porém, isso não é grande coisa - tenho certeza que os benefícios de poder tirar proveito do goto
JavaScript vão sobrecarregá-lo.
Todo o link acima que leva à biblioteca goto.js está TODO MORTO, aqui estão os links necessários:
goto.js (descompactado) --- parseScripts.js (descompactado)
No Goto.js :
PS Para quem está se perguntando (até agora um total de zero pessoas), Summer of Goto é um termo popularizado por Paul Irish, enquanto discute esse script e a decisão do PHP de adicionar goto em seu idioma.
E para aqueles que não reconhecem imediatamente que tudo isso é uma piada, por favor, perdoe-me. <- (seguro).
goto
provavelmente está subutilizado. Isso cria alguns padrões muito bons de manipulação de erros. Caramba, nós usamos switch
, que está goto
em tudo, exceto no nome, e ninguém sofre de barriga.
Não. Eles não incluíram isso no ECMAScript:
ECMAScript não possui instrução goto.
goto
se encaixaria perfeitamente bem em cocktail de javascript de estúpido "apresenta" :)
goto
é uma palavra-chave reservada para uso futuro, no entanto. Podemos apenas esperar :)
goto
seria útil quando você deseja retornar de uma função aninhada. Por exemplo, ao usar underscore.js, você fornece uma função anônima ao iterar sobre matrizes. Você não pode retornar de dentro de uma função, por isso goto end;
seria útil.
Na verdade, eu vejo que ECMAScript (JavaScript) tem uma instrução goto. No entanto, o JavaScript goto tem dois sabores!
Os dois tipos de JavaScript do goto são chamados de continue e de interrupção. Não há palavras-chave "ir" em JavaScript. O goto é realizado em JavaScript usando as palavras-chave break e continue.
E isso é mais ou menos explicitamente declarado no site da w3schools aqui http://www.w3schools.com/js/js_switch.asp .
Acho que a documentação do rotulado continue e rotulada como um pouco estranhamente expressa.
A diferença entre o rotulado continuar e o rotulado é onde eles podem ser usados. O continuar rotulado só pode ser usado dentro de um loop while. Veja w3schools para mais informações.
===========
Outra abordagem que funcionará é ter uma declaração while gigante com uma declaração switch 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
e também continue
pode ser usado em for
loops. Mas eles realmente não são equivalentes ao goto
fato de estarem bloqueados na estrutura do (s) loop (s) relacionado (s), em comparação com o goto
que pode, é claro - nas linguagens que o possui - ir para qualquer lugar.
No JavaScript clássico, você precisa usar loops do-while para obter esse tipo de código. Presumo que talvez você esteja gerando código para outra coisa.
A maneira de fazer isso, como no back-end do bytecode para JavaScript, é agrupar todos os destinos de rótulo em um tempo rotulado "rotulado".
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);
Todo loop do-while rotulado que você usa dessa maneira cria os dois pontos de rótulo para um rótulo. Um na parte superior e outro no final do loop. Pular para trás usa continuar e pular para frente usa pausa.
// 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)
Infelizmente, não há outra maneira de fazê-lo.
Código de exemplo normal:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
Por exemplo, digamos que o código seja codificado para bytecodes, agora você deve colocar os bytecodes em JavaScript para simular seu back-end para algum 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)
Portanto, o uso dessa técnica faz o trabalho bem para propósitos simples. Fora isso, não muito mais você pode fazer.
Para Javacript normal, você não precisa mais usar goto, portanto provavelmente deve evitar essa técnica aqui, a menos que esteja traduzindo especificamente outro código de estilo para executar em JavaScript. Suponho que é assim que eles conseguem o kernel do Linux inicializar em JavaScript, por exemplo.
NOTA! Esta é toda uma explicação ingênua. Para o back-end Js adequado dos bytecodes, considere também examinar os loops antes de emitir o código. Muitos loops while simples podem ser detectados como tal e você pode usar loops em vez de ir para o goto.
continue
em um do ... while
loop continua para a condição de verificação . O inverso goto
aqui usando, do ... while (0)
portanto, não funciona. ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoop
isso funcionar. E loop principal: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop)
github.com/patarapolw/HanziLevelUp/blob/…
Essa é uma pergunta antiga, mas como o JavaScript é um alvo em movimento - é possível no ES6 na implementação que suporte chamadas de cauda adequadas. Nas implementações com suporte para chamadas finais apropriadas, você pode ter um número ilimitado de chamadas finais ativas (ou seja, chamadas finais não "aumentam a pilha").
A goto
pode ser considerado como uma chamada de cauda sem parâmetros.
O exemplo:
start: alert("RINSE");
alert("LATHER");
goto start
pode ser escrito como
function start() { alert("RINSE");
alert("LATHER");
return start() }
Aqui a chamada para start
está na posição final, portanto não haverá estouros de pilha.
Aqui está um exemplo mais complexo:
label1: A
B
if C goto label3
D
label3: E
goto label1
Primeiro, dividimos a fonte em blocos. Cada etiqueta indica o início de um novo bloco.
Block1
label1: A
B
if C goto label3
D
Block2
label3: E
goto label1
Precisamos amarrar os blocos usando gotos. No exemplo, o bloco E segue D, então adicionamos um goto label3
depois de D.
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
Agora, cada bloco se torna uma função e cada goto se torna uma chamada final.
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
Para iniciar o programa, use label1()
.
A reescrita é puramente mecânica e, portanto, pode ser feita com um sistema macro como o sweet.js, se necessário.
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;
}
Que tal um for
loop? Repita quantas vezes quiser. Ou um while
loop, repita até que uma condição seja atendida. Existem estruturas de controle que permitem repetir o código. Lembro-me GOTO
no Basic ... fez um código tão ruim! As linguagens de programação modernas oferecem melhores opções que você pode realmente manter.
Existe uma maneira de fazer isso, mas ele precisa ser planejado com cuidado. Tomemos, por exemplo, o seguinte 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."
Em seguida, crie seu JavaScript para inicializar todas as variáveis primeiro, seguido de uma chamada de função inicial para iniciar a bola rolando (executamos essa chamada de função inicial no final) e configure funções para cada conjunto de linhas que você sabe que serão executadas a uma unidade.
Siga isto com a chamada de função 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();
O resultado nesta instância é:
a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
Geralmente, eu preferiria não usar o GoTo para facilitar a leitura. Para mim, é uma desculpa ruim para programar funções iterativas simples em vez de ter que programar funções recursivas, ou melhor ainda (se houver medo de coisas como um Stack Overflow), suas verdadeiras alternativas iterativas (que às vezes podem ser complexas).
Algo assim faria:
while(true) {
alert("RINSE");
alert("LATHER");
}
Isso mesmo, há um loop infinito. A expressão ("true") dentro dos parênteses da cláusula while é o que o mecanismo Javascript verificará - e se a expressão for verdadeira, manterá o loop em execução. Escrever "true" aqui sempre é avaliado como true, portanto, um loop infinito.
Claro, usando a switch
construção, você pode simular goto
em JavaScript. Infelizmente, o idioma não fornece goto
, mas isso é uma substituição suficiente.
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
}
}
Você provavelmente deve ler alguns tutoriais JS como este um .
Não tenho certeza se goto
existe em JS, mas, de qualquer forma, ele incentiva um estilo de codificação ruim e deve ser evitado.
Você poderia fazer:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
Você pode simplesmente usar uma função:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
Para obter funcionalidades semelhantes a goto, mantendo a pilha de chamadas limpa, estou 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();
}
// ...
Observe que esse código é lento, pois as chamadas de função são adicionadas à fila de tempos limite, que é avaliada posteriormente, no loop de atualização do navegador.
Observe também que você pode passar argumentos (usando setTimeout(func, 0, arg1, args...)
no navegador mais recente que o IE9 ou setTimeout(function(){func(arg1, args...)}, 0)
em navegadores mais antigos.
AFAIK, você nunca deve encontrar um caso que exija esse método, a menos que seja necessário pausar um loop não paralelo em um ambiente sem suporte a assíncrono / espera.
ir para o início e fim de todos os fechamentos dos pais
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);
}
}
Outra maneira alternativa de conseguir o mesmo é usar as chamadas de cauda. Mas, não temos nada parecido em JavaScript. Geralmente, o goto é realizado em JS usando as duas palavras-chave abaixo. quebrar e continuar , referência: Goto Statement in JavaScript
Aqui está um exemplo:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}