web-dev-qa-db-fra.com

Comment utiliser goto en Javascript?

J'ai du code que je dois absolument implémenter en utilisant goto. Par exemple, je veux écrire un programme comme celui-ci:

start:
alert("RINSE");
alert("LATHER");
repeat: goto start

Y a-t-il un moyen de faire cela en Javascript?

116
Peter Olson

Absolument! Il existe un projet appelé Summer of Goto qui vous permet d'utiliser JavaScript à son plein potentiel et qui révolutionnera la manière dont vous pouvez écrire votre code.

Cet outil de prétraitement JavaScript vous permet de créer une étiquette, puis de l’utiliser avec la syntaxe suivante:

[lbl] <label-name>
goto <label-name>

Par exemple, l’exemple de la question peut s’écrire comme suit:

[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;

Notez que vous n'êtes pas limité à de simples programmes triviaux comme un cycle sans fin LATHERRINSE: les possibilités offertes par goto sont infinies et vous pouvez même créer un message Hello, world!. sur la console JavaScript 538 fois, comme ceci:

var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;

Vous pouvez en savoir plus sur la façon dont goto est implémenté , mais en gros, il effectue un prétraitement JavaScript qui tire parti du fait que vous pouvez simuler un goto avec une boucle étiquetée while . Alors, quand vous écrivez le "Bonjour, le monde!" programme ci-dessus, il est traduit à quelque chose comme ça:

var i = 0;
start: while(true) {
  console.log("Hello, world!");
  i++;
  if(i < 538) continue start;
  break;
}

Ce processus de prétraitement présente certaines limites, car les boucles while ne peuvent pas s'étendre sur plusieurs fonctions ou blocs. Ce n'est pas grave, cependant - je suis sûr que les avantages de pouvoir tirer parti de goto en JavaScript vous submergeront complètement.

Tout le lien ci-dessus qui mène à la bibliothèque goto.js est ALL DEAD, voici les liens nécessaires:

goto.js (non compressé) --- parseScripts.js (non compressé)

De Goto.js :

P.S. Pour ceux qui s’interrogent (jusqu’à présent sur zéro), Summer of Goto est un terme popularisé par Paul Irish, tout en discutant de ce script et de la décision de PHP d’ajouter goto à leur langue.

Et pour ceux qui ne reconnaissent pas immédiatement que toute cette affaire est une blague, veuillez me pardonner. <- (assurance).

143
Peter Olson

No. Ils n'incluaient pas cela dans ECMAScript:

ECMAScript n'a pas de déclaration goto.

108
pimvdb

En fait, je vois que ECMAScript (JavaScript) DOIT INDEED avoir une instruction goto. Cependant, le JavaScript a deux saveurs!

Les deux versions JavaScript de goto sont appelées continuer et étiquetées break. Il n'y a pas de mot-clé "goto" en JavaScript. La lecture s'effectue en JavaScript à l'aide des mots clés break et continue.

Et ceci est plus ou moins explicitement indiqué sur le site Web de w3schools ici http://www.w3schools.com/js/js_switch.asp .

Je trouve la documentation de continuer étiquetée et pause étiquetée un peu maladroitement exprimée.

La différence entre la continuation marquée et la pause marquée est l'endroit où elles peuvent être utilisées. Le libellé continue ne peut être utilisé que dans une boucle while. Voir w3schools pour plus d’informations.

===========

Une autre approche qui fonctionne est d’avoir une déclaration while géante avec une déclaration switch géant à l’intérieur:

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

}
33
Indinfer

En JavaScript classique, vous devez utiliser des boucles do-while pour obtenir ce type de code. Je suppose que vous générez peut-être du code pour autre chose.

La façon de le faire, comme pour le bytecode de retour en JavaScript, consiste à envelopper chaque cible de libellé dans un do-while "étiqueté".

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

Chaque boucle do-while étiquetée que vous utilisez ainsi crée en réalité les deux points d'étiquette pour l'étiquette. Un au sommet et un à la fin de la boucle. Le retour en arrière continue et le saut en avant est utilisé.

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

Malheureusement, il n'y a pas d'autre moyen de le faire.

Exemple de code normal:

while (x < 10 && Ok) {
  z = 0;
  while (z < 10) {
    if (!DoStuff()) {
      Ok = FALSE;
      break;
    }
    z++;
  }
  x++;
} 

Donc, supposons que le code soit codé en octets alors vous devez maintenant les mettre en JavaScript pour simuler votre backend dans un but précis.

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

Donc, en utilisant cette technique fait le travail bien à des fins simples. En dehors de cela, vous ne pouvez pas faire grand chose d'autre.

Pour Javacript normal, vous ne devriez pas avoir besoin d'utiliser goto, vous devriez donc probablement éviter cette technique, sauf si vous traduisez spécifiquement un autre code de style pour qu'il soit exécuté en JavaScript. Je suppose que c'est ainsi qu'ils obtiennent le noyau Linux pour démarrer en JavaScript, par exemple.

REMARQUE! Ceci est toute explication naïve. Pour un système Js approprié, vous pouvez également examiner les boucles avant de sortir le code. De nombreuses boucles while simples peuvent être détectées en tant que telles et vous pouvez alors utiliser des boucles au lieu de goto.

30
user1401452
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;
}
14
Henri Gourvest

C'est une vieille question, mais comme JavaScript est une cible en mouvement, il est possible dans ES6 lors de l'implémentation de prendre en charge les appels de fin appropriés. Sur les implémentations prenant en charge les appels de fin de ligne appropriés, vous pouvez avoir un nombre illimité d’appels de fin actifs (c.-à-d. Que les appels de fin ne "grossissent pas la pile").

Un goto peut être considéré comme un appel final sans paramètre.

L'exemple:

start: alert("RINSE");
       alert("LATHER");
       goto start

peut être écrit comme

 function start() { alert("RINSE");
                    alert("LATHER");
                    return start() }

Ici, l'appel à start est en position de fin, il n'y aura donc pas de débordement de pile.

Voici un exemple plus complexe:

 label1:   A
           B
           if C goto label3
           D
 label3:   E
           goto label1

Tout d'abord, nous avons divisé la source en blocs. Chaque étiquette indique le début d'un nouveau bloc.

 Block1
     label1:   A
               B
               if C goto label3
               D

  Block2    
     label3:   E
               goto label1

Nous devons relier les blocs entre eux à l'aide de gotos. Dans l'exemple, le bloc E suit D, nous ajoutons donc un goto label3 après D.

 Block1
     label1:   A
               B
               if C goto label2
               D
               goto label2

  Block2    
     label2:   E
               goto label1

Maintenant, chaque bloc devient une fonction et chaque goto devient un appel final.

 function label1() {
               A
               B
               if C then return( label2() )
               D
               return( label2() )
 }

 function label2() {
               E
               return( label1() )
 }

Pour lancer le programme, utilisez label1().

La réécriture est purement mécanique et peut donc être effectuée avec un système macro tel que sweet.js si besoin est.

12
soegaard

Que diriez-vous d'une boucle for? Répétez autant de fois que vous le souhaitez. Ou une boucle while, répétez l'opération jusqu'à ce qu'une condition soit remplie. Il existe des structures de contrôle qui vous permettront de répéter le code. Je me souviens de GOTO en Basic ... cela créait un tel code! Les langages de programmation modernes vous offrent de meilleures options que vous pouvez réellement gérer.

8
Surreal Dreams

Il existe un moyen de le faire, mais cela doit être planifié avec soin. Prenons par exemple le programme QBASIC suivant:

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

Créez ensuite votre code JavaScript pour initialiser toutes les variables, puis effectuez un appel de fonction initial pour démarrer le processus (nous exécutons cet appel de fonction initial à la fin), puis configurez les fonctions pour chaque ensemble de lignes dans lequel vous savez qu'il sera exécuté. la seule unité.

Suivez ceci avec l'appel de fonction initial ...

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

Le résultat dans cet exemple est:

a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
7
Eliseo d'Annunzio

Bien sûr, en utilisant la construction switch, vous pouvez simuler goto en JavaScript. Malheureusement, le langage ne fournit pas goto, mais c'est un assez bon remplacement.

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
Konrad Borowski

Vous devriez probablement lire quelques tutoriels JS comme ceci n.

Vous n'êtes pas sûr que goto existe dans JS, mais dans tous les cas, cela encourage un mauvais style de codage et doit être évité.

Vous pourriez faire:

while ( some_condition ){
    alert('RINSE');
    alert('LATHER');
}
5
Jovan Perovic

Généralement, je préférerais ne pas utiliser GoTo pour une mauvaise lisibilité. Pour moi, c'est une mauvaise excuse pour programmer des fonctions itératives simples au lieu d'avoir à programmer des fonctions récursives, ou même mieux (si l'on craint un débordement de pile, par exemple), leurs véritables alternatives itératives (qui peuvent parfois être complexes).

Quelque chose comme ça ferait:

while(true) {
   alert("RINSE");
   alert("LATHER");
}

Ce droit là est une boucle infinie. L'expression ("true") à l'intérieur des parenthèses de la clause while correspond à ce que le moteur Javascript va rechercher. Si l'expression est true, la boucle sera exécutée. Écrire "vrai" ici est toujours considéré comme vrai, d'où une boucle infinie.

Vous pouvez simplement utiliser une fonction:

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

Pour obtenir une fonctionnalité de type goto tout en gardant la pile d'appels propre, j'utilise cette méthode:

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

// ...

Veuillez noter que ce code est lent car les appels de fonction sont ajoutés à la file d'attente de dépassement de délai, qui est évaluée ultérieurement, dans la boucle de mise à jour du navigateur.

Veuillez également noter que vous pouvez passer des arguments (en utilisant setTimeout(func, 0, arg1, args...) dans un navigateur plus récent que IE9 ou setTimeout(function(){func(arg1, args...)}, 0) dans les navigateurs plus anciens.

Autant que je sache, vous ne devriez jamais vous retrouver dans un cas qui nécessite cette méthode, sauf si vous devez suspendre une boucle non parallélisable dans un environnement sans prise en charge asynchrone/wait.

4
pzmarzly

aller au début et à la fin de toutes les fermetures de parents

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
Tito100
// 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);
            }
        }
1
user10780188