Como posso usar goto em Javascript?


127

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?


Goto seria conviniend para javascript compilado. Eu tenho uma JVM escrita em JavaScript. Seria muito melhor e mais curto com a declaração goto.
neoexpert 27/01

Respostas:


151

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 RINSEciclo de repetição sem fim - as possibilidades oferecidas gotosã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 gotoJavaScript 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).


10
@SurrealDreams Pode ser uma piada, mas na verdade funciona. Você pode clicar nos links jsFiddle e ver se eles realmente funcionam.
31812 Peter Olson

22
O artigo é ligada a afirma, na verdade, é uma piada :)
pimvdb

6
@ PeterOlson, mas o stackoverflow tem como objetivo ajudar as pessoas a aprender programação. As perguntas e respostas devem ser úteis para isso. Ninguém está sendo ajudado por isso.
GoldenNewby

5
@ShadowWizard Esta resposta já está cercada por muitas isenções de responsabilidade e pessoas falando sobre por que isso não deve ser usado. Não sinto vergonha de deixar as pessoas que deliberadamente ignoram que enfrentam as consequências de fazê-lo.
Peter Olson

8
+1 para @AlexMills. Honestamente, acho que gotoprovavelmente está subutilizado. Isso cria alguns padrões muito bons de manipulação de erros. Caramba, nós usamos switch, que está gotoem tudo, exceto no nome, e ninguém sofre de barriga.
0x1mason

122

Não. Eles não incluíram isso no ECMAScript:

ECMAScript não possui instrução goto.


1
Eu queria saber se o GOTO seria útil durante a depuração do JavaScript. Afaik, apenas o IE fornece GOTO em seu depurador ... e eu realmente encontrei um caso de uso para ele, mas não tenho certeza se poderia ser útil em geral ... pular enquanto depurando JavaScript. O que você acha?
Šime Vidas

3
@ Šime Vidas: Não tenho certeza se a depuração com a funcionalidade goto é útil. Basicamente, você estaria mexendo com o caminho do código de uma maneira que nunca aconteceria sem a depuração.
Pimvdb

12
Que pena ... IMHO gotose encaixaria perfeitamente bem em cocktail de javascript de estúpido "apresenta" :)
Yuriy Nakonechnyy

4
gotoé uma palavra-chave reservada para uso futuro, no entanto. Podemos apenas esperar :)
Azmisov

4
gotoseria ú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.
Hubro 24/03

31

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. ...
    }

}

9
"O rótulo continue só pode ser usado dentro de um loop while." - Não, rotulado breake também continuepode ser usado em forloops. Mas eles realmente não são equivalentes ao gotofato de estarem bloqueados na estrutura do (s) loop (s) relacionado (s), em comparação com o gotoque pode, é claro - nas linguagens que o possui - ir para qualquer lugar.
Nnnnnn 26/04

31

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.


1
continueem um do ... whileloop continua para a condição de verificação . O inverso gotoaqui usando, do ... while (0)portanto, não funciona. ecma-international.org/ecma-262/5.1/#sec-12.6.1
ZachB

1
Não funciona Eu tenho que fazer let doLoopisso funcionar. E loop principal: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop) github.com/patarapolw/HanziLevelUp/blob/…
Polv

15

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 gotopode 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 startestá 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 label3depois 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.


"é possível no ES6 na implementação que suporte chamadas de cauda apropriadas". As chamadas finais do AFAIK estão desativadas em todos os principais navegadores.
JD

O Safari suporta chamadas de cauda adequadas, acredito. No momento em que a resposta foi dada, era possível ativar chamadas de cauda adequadas no Chrome por meio de uma opção de linha de comando. Vamos torcer para que eles reconsiderem - ou pelo menos comece a apoiar chamadas de chamada explicitamente marcadas.
soegaard

Chamadas explicitamente marcadas provavelmente fariam todo mundo feliz.
JD

14
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;
}

8

Que tal um forloop? Repita quantas vezes quiser. Ou um whileloop, repita até que uma condição seja atendida. Existem estruturas de controle que permitem repetir o código. Lembro-me GOTOno Basic ... fez um código tão ruim! As linguagens de programação modernas oferecem melhores opções que você pode realmente manter.


O ciclo infinito de produção: Protótipo, zero, melhor protótipo, zero, melhor melhor protótipo, zero. A manutenção geralmente é uma falácia. Não é necessário manter muitos códigos. A maioria dos códigos é reescrita, não mantida.
Pacerier

7

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.

@JonHarrop, existe um tamanho máximo de pilha que o JavaScript pode manipular antes de a pilha estourar?
Eliseo d'Annunzio 20/10

1
Sim e parece ser extremamente pequeno. Muito menor do que qualquer outro idioma que eu já usei.
JD

7

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.


7

Claro, usando a switchconstrução, você pode simular gotoem 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
  }
}

5

Você provavelmente deve ler alguns tutoriais JS como este um .

Não tenho certeza se gotoexiste 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');
}

4

Você pode simplesmente usar uma função:

function hello() {
    alert("RINSE");
    alert("LATHER");
    hello();
}

5
É uma péssima idéia, pois continuará pressionando o endereço de retorno na pilha de chamadas até que o sistema fique sem memória.
Paul Hutchinson

1
De fato, porém, o usuário terá CTRL-ALT-DELETEd muito antes dos intermináveis ​​diálogos RINSE-LATHER!
Shayne

4

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.


1
Desagradável. Eu amo isso. FWIW, essa técnica é chamada de trampolim.
JD

Eu posso verificar isso funciona. Estou transpilando manualmente algumas instruções HP RPN com GTO, o que leva a uma recursão profunda quando implementada como chamadas de função; o método setTimeout () mostrado acima recolhe a pilha e a recursão não é mais um problema. Mas é muito mais lento. Ah, e eu estou fazendo isso no Node.js.
Jeff Lowery

3

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);

3
// 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);
            }
        }

2

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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.