Как я могу использовать goto в Javascript?

У меня есть код, который я обязательно должен реализовать, используя goto, Например, я хочу написать такую ​​программу:

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

Есть ли способ сделать это в Javascript?

18 ответов

Решение

Абсолютно! Существует проект под названием Summer of Goto, который позволяет вам использовать JavaScript в полной мере и революционизировать способ написания кода.

Этот инструмент предварительной обработки JavaScript позволяет вам создать метку и затем перейти к ней, используя следующий синтаксис:

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

Например, пример в вопросе может быть записан следующим образом:

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

Обратите внимание, что вы не ограничены простыми тривиальными программами, такими как бесконечные LATHERRINSE цикл повтора - возможности, предоставляемые goto бесконечны, и вы даже можете сделать Hello, world! сообщение на консоль JavaScript 538 раз, например:

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

Вы можете прочитать больше о том, как реализован goto, но в основном он выполняет некоторую предварительную обработку JavaScript, которая использует тот факт, что вы можете смоделировать goto с пометкой while петля Итак, когда вы пишете "Привет, мир!" Программа выше, она переводится в нечто вроде этого:

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

У этого процесса предварительной обработки есть некоторые ограничения, поскольку циклы while не могут распространяться на несколько функций или блоков. Это не имеет большого значения, хотя - я уверен, что преимущества того, чтобы иметь возможность воспользоваться goto в JavaScript вас совершенно не хватит.

Все вышеперечисленные ссылки, которые ведут в библиотеку goto.js, ВСЕ МЕРТВЫ, вот ссылки, необходимые:

goto.js (без сжатия) --- parseScripts.js (без сжатия)

Из Goto.js:

PS Для тех, кто интересуется (до сих пор всего ноль человек), Summer of Goto - это термин, который был популяризирован Полом Айришем при обсуждении этого скрипта и решения PHP добавить goto в их язык.

И для тех, кто не сразу понимает, что все это шутка, пожалуйста, прости меня. <- (страхование).

Нет. Они не включили это в ECMAScript:

ECMAScript не имеет оператора goto.

В классическом JavaScript вам нужно использовать циклы do-while для достижения такого типа кода. Я предполагаю, что вы, возможно, генерируете код для чего-то другого.

Способ сделать это, например, для байт-кода бэкэнда в JavaScript, - обернуть каждую цель метки в "помеченное" задание.

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

Каждый помеченный цикл do-while, который вы используете таким образом, фактически создает две точки метки для одной метки. Один наверху и один в конце цикла. Прыжок назад использует продолжение, а прыжок вперед - разрыв.

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

К сожалению, нет другого способа сделать это.

Нормальный пример кода:

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

Допустим, код закодирован в байт-коды, поэтому теперь вы должны поместить байт-коды в JavaScript, чтобы с какой-то целью имитировать ваш бэкэнд.

Стиль 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)

Таким образом, использование этой техники отлично подходит для простых целей. Кроме этого не так много вы можете сделать.

Для обычного Javacript вам не нужно использовать goto когда-либо, поэтому вам, вероятно, следует избегать этой техники здесь, если вы специально не переводите другой код стиля для запуска на JavaScript. Я предполагаю, что именно так они получают ядро ​​Linux для загрузки на JavaScript, например.

НОТА! Это все наивное объяснение. Для правильного Js бэкэнда байт-кодов также рассмотрите проверку циклов перед выводом кода. Многие простые циклы while могут быть обнаружены как таковые, и тогда вы можете использовать циклы вместо goto.

На самом деле, я вижу, что ECMAScript (JavaScript) действительно имеет оператор goto. Тем не менее, JavaScript Goto имеет два вида!

Два JavaScript-варианта goto называются "помечены как продолжение" и "помечены как разрыв". В JavaScript нет ключевого слова "goto". Goto выполняется в JavaScript с использованием ключевых слов break и continue.

И это более или менее четко указано на веб-сайте w3schools http://www.w3schools.com/js/js_switch.asp.

Я нахожу документацию с надписью "продолжить" и с надписью "разрыв" несколько неловко выраженной.

Разница между помеченным продолжением и помеченным разрывом заключается в том, где они могут быть использованы. Помеченный продолжить можно использовать только внутри цикла while. Смотрите w3schools для получения дополнительной информации.

===========

Другой подход, который сработает, - создать гигантское выражение while с гигантским оператором switch внутри:

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

}

Это старый вопрос, но поскольку JavaScript является движущейся целью - в ES6 это возможно при реализации, поддерживающей надлежащие вызовы хвоста. В реализациях с поддержкой правильных оконечных вызовов у вас может быть неограниченное количество активных оконечных вызовов (т. Е. Конечные вызовы не "наращивают стек").

goto можно рассматривать как хвостовой вызов без параметров.

Пример:

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

можно записать как

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

Здесь призыв к start находится в хвостовой позиции, поэтому переполнения стека не будет.

Вот более сложный пример:

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

Сначала мы разбиваем источник на блоки. Каждая метка указывает на начало нового блока.

 Block1
     label1:   A
               B
               if C goto label3
               D

  Block2    
     label3:   E
               goto label1

Нам нужно связать блоки вместе, используя gotos. В примере блок E следует за D, поэтому мы добавляем goto label3 после Д.

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

  Block2    
     label2:   E
               goto label1

Теперь каждый блок становится функцией, а каждое goto становится хвостовым вызовом.

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

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

Чтобы запустить программу, используйте label1(),

Перезапись носит чисто механический характер и может быть выполнена с помощью макросистемы, такой как sweet.js, если это необходимо.

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

Конечно, используя switch построить вы можете моделировать goto в JavaScript. К сожалению, язык не обеспечивает goto, но это достаточно хорошая замена.

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

Как насчет for цикл? Повторите столько раз, сколько хотите. Или while цикл, повторять, пока не будет выполнено условие. Существуют управляющие структуры, которые позволят вам повторить код. Я помню GOTO в Basic... он сделал такой плохой код! Современные языки программирования предоставляют вам лучшие возможности, которые вы можете поддерживать.

Есть способ, которым это может быть сделано, но это должно быть тщательно спланировано. Возьмем для примера следующую программу 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."

Затем создайте свой JavaScript, чтобы сначала инициализировать все переменные, а затем выполнить начальный вызов функции, чтобы начать вращение шара (мы выполняем этот первоначальный вызов функции в конце), и настроить функции для каждого набора строк, который, как вы знаете, будет выполняться в один блок.

Следуйте этому с начальным вызовом функции...

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

Результат в этом случае:

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

Как правило, я бы предпочел не использовать GoTo для плохой читабельности. Для меня это плохое оправдание для программирования простых итеративных функций вместо того, чтобы программировать рекурсивные функции, или даже лучше (если боятся таких вещей, как переполнение стека), их истинных итерационных альтернатив (которые иногда могут быть сложными).

Что-то вроде этого сделало бы:

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

Это право есть бесконечный цикл. Выражение ("истина") внутри паратезов предложения while - это то, что проверяет движок Javascript - и если выражение истинно, оно будет поддерживать цикл работающим. Запись "истина" здесь всегда приводит к истине, следовательно, бесконечный цикл.

Вы, вероятно, должны прочитать некоторые учебники по JS, как этот.

Не уверен если goto существует в JS вообще, но, в любом случае, это поощряет плохой стиль кодирования и его следует избегать.

Вы могли бы сделать:

while ( some_condition ){
    alert('RINSE');
    alert('LATHER');
}

Вы можете просто использовать функцию:

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

Для достижения функциональности goto-like, сохраняя стек вызовов чистым, я использую этот метод:

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

// ...

Обратите внимание, что этот код работает медленно, поскольку вызовы функций добавляются в очередь тайм-аутов, которая оценивается позже, в цикле обновления браузера.

Также обратите внимание, что вы можете передавать аргументы (используя setTimeout(func, 0, arg1, args...) в браузере новее, чем IE9, или setTimeout(function(){func(arg1, args...)}, 0) в старых браузерах.

AFAIK, вы никогда не должны сталкиваться с делом, которое требует этот метод, если вам не нужно приостанавливать непараллельный цикл в среде без поддержки async/await.

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

Начало и конец всех закрытий родителей

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

Другой альтернативный способ добиться того же - использовать хвостовые вызовы. Но у нас нет ничего подобного в JavaScript. Таким образом, в общем, goto выполняется в JS с использованием следующих двух ключевых слов.прервать ипродолжить, ссылка: Goto Statement на JavaScript

Вот пример:

var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}

Бросаю на это свои 2 цента, так как нашел собственное решение без циклов и загромождающих повсюду функций:

      function rinseLatherSwitch(label) 
{
    function goto(to)
    {
        switch(to)
        {
            case "rinse": alert("RINSE"); return goto("lather");
            case "lather": alert("LATHER"); return goto("end");
            case "end": break;
        }
    }

    return goto(label);
}

rinseLatherSwitch("rinse");

У этого формата есть 3 преимущества:

  1. Структура кода соответствует переключателям других языков с помощью goto(например, C#).
  2. Все это замкнуто в одной функции, поэтому не загромождает другой код.
  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);
            }
        }

// Output is:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// Notice how it skips both "i = 1, j = 1" and "i = 1, j = 2"
Другие вопросы по тегам