У меня есть код, который я обязательно должен реализовать goto
. Например, я хочу написать такую программу:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Есть ли способ сделать это в Javascript?
У меня есть код, который я обязательно должен реализовать goto
. Например, я хочу написать такую программу:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Есть ли способ сделать это в Javascript?
Ответы:
Абсолютно! Существует проект под названием Summer of Goto, который позволяет вам использовать JavaScript в полном объеме и революционизирует способ написания кода.
Этот инструмент предварительной обработки JavaScript позволяет вам создать метку, а затем перейти к ней, используя следующий синтаксис:
[lbl] <label-name>
goto <label-name>
Например, пример в вопросе можно записать так:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Обратите внимание, что вы не ограничены только простыми тривиальными программами, такими как бесконечный LATHER
RINSE
цикл повторения - возможности, предоставляемые ими 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 в свой язык.
А тем, кто не сразу понимает, что все это шутка, прошу меня простить. <- (страхование).
goto
используется недостаточно. Это создает очень хорошие шаблоны обработки ошибок. Черт возьми, мы употребляем switch
, что goto
во всем, кроме названия, и ни у кого не болит живот.
Нет. Они не включили это в ECMAScript:
В ECMAScript нет оператора goto.
goto
отлично вписалось бы в коктейль дурацких «фич» javascript :)
goto
однако это зарезервированное ключевое слово для использования в будущем. Нам остается только надеяться :)
goto
было бы полезно, когда вы хотите вернуться из вложенной функции. Например, при использовании underscore.js вы предоставляете анонимную функцию при переборе массивов. Вы не можете вернуться изнутри такой функции, поэтому goto end;
было бы полезно.
На самом деле, я вижу, что в ECMAScript (JavaScript) ДЕЙСТВИТЕЛЬНО есть инструкция goto. Однако у JavaScript goto есть две разновидности!
Две разновидности goto в JavaScript называются «continue» и «break». В JavaScript нет ключевого слова "goto". Переход выполняется в JavaScript с использованием ключевых слов break и continue.
И это более или менее четко указано на сайте w3schools здесь http://www.w3schools.com/js/js_switch.asp .
Я нахожу документацию помеченного продолжения и помеченного перерыва несколько неуклюже выраженной.
Разница между помеченным продолжением и помеченным разрывом заключается в том, где они могут использоваться. Отмеченное continue можно использовать только внутри цикла 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. ...
}
}
break
и continue
может использоваться в for
петлях. Но на самом деле они не эквивалентны тому, goto
что они заблокированы в структуре связанных циклов, по сравнению с goto
которыми, конечно, на языках, в которых они есть, могут перемещаться куда угодно.
В классическом JavaScript вам нужно использовать циклы do-while для достижения этого типа кода. Я предполагаю, что вы, возможно, генерируете код для чего-то другого.
Способ сделать это, как и для байт-кода в JavaScript, состоит в том, чтобы обернуть каждую цель метки в «помеченный» do-while.
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, который вы используете таким образом, фактически создает две точки метки для одной метки. Один вверху и один в конце петли. Для прыжка назад используется continue, а для прыжка вперед - break.
// 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.
continue
в do ... while
цикле переходит к условию проверки . Обратное goto
здесь, используяdo ... while (0)
не работает. ecma-international.org/ecma-262/5.1/#sec-12.6.1
let doLoop
это сработало. И основной цикл: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop)
github.com/patarapolw/HanziLevelUp/blob/…
Это старый вопрос, но поскольку JavaScript - это движущаяся цель, в ES6 это возможно при реализации, которая поддерживает правильные хвостовые вызовы. В реализациях с поддержкой правильных хвостовых вызовов вы можете иметь неограниченное количество активных хвостовых вызовов (т.е. хвостовые вызовы не «увеличивают стек»).
A 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, поэтому мы добавляем a goto label3
после D.
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
Теперь каждый блок становится функцией, а каждый переход становится хвостовым вызовом.
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;
}
Как насчет 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 будет проверять - и если выражение истинно, он продолжит выполнение цикла. Написание здесь «истина» всегда означает истину, отсюда бесконечный цикл.
Конечно, с помощью 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
}
}
Вы , вероятно , следует прочитать некоторые JS учебники как этот один .
Не уверен если goto
существует в JS, но, в любом случае, он поощряет плохой стиль кодирования, и его следует избегать.
Вы могли:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
Вы можете просто использовать функцию:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
Чтобы достичь функциональности, подобной goto, при сохранении чистоты стека вызовов, я использую этот метод:
// 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.
goto начало и конец всех родительских закрытий
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);
}
}
Другой альтернативный способ добиться того же - использовать хвостовые вызовы. Но в JavaScript ничего подобного нет. Итак, как правило, goto выполняется в JS с использованием следующих двух ключевых слов. прервать и продолжить , ссылка: Оператор Goto в JavaScript
Вот пример:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}