Javascript에서 goto를 어떻게 사용합니까?


127

을 사용하여 구현 해야하는 코드가 goto있습니다. 예를 들어 다음과 같은 프로그램을 작성하고 싶습니다.

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

자바 스크립트로 그렇게 할 수 있습니까?


goto는 컴파일 된 자바 스크립트에 적합합니다. JavaScript로 작성된 JVM이 있습니다. goto 문을 사용하면 성능이 뛰어나고 짧을 것입니다.
neoexpert

답변:


151

물론! 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 구현 방법에 대한 자세한 내용을 읽을 수 있지만 기본적으로 레이블이 지정된 while루프 로 goto를 시뮬레이션 할 수 있다는 사실을 활용하는 JavaScript 전처리를 수행 합니다 . "Hello, world!"라고 쓸 때 위의 프로그램에서 다음과 같이 번역됩니다.

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

while 루프는 여러 기능이나 블록에 걸쳐 확장 될 수 없기 때문에이 전처리 프로세스에는 몇 가지 제한 사항이 있습니다. 그럼에도 불구하고 큰 문제 goto는 아닙니다. JavaScript를 활용할 수있는 이점이 당신을 압도 할 것입니다.

goto.js 라이브러리로 연결되는 위의 모든 링크는 ALL DEAD입니다. 필요한 링크는 다음과 같습니다.

goto.js (비 압축) --- parseScripts.js (비 압축)

에서 Goto.js :

추신 : 궁금한 사람 (지금까지 총 0 명)을 위해, Goto의 Summer는 Paul Irish가 대중화 한 용어이며,이 스크립트와 자신의 언어에 goto를 추가하려는 PHP의 결정에 대해 논의합니다.

그리고이 모든 것이 농담이라는 것을 즉시 인식하지 못하는 사람들을 위해, 저를 용서하십시오. <— (보험).


10
@SurrealDreams 농담 일지 모르지만 실제로 작동합니다. jsFiddle 링크를 클릭하면 실제로 작동하는지 확인할 수 있습니다.
피터 올슨

22
당신이 링크 한 기사는 실제로 농담이라고 말합니다 :)
pimvdb

6
@PeterOlson, 그러나 stackoverflow는 사람들이 프로그래밍을 배우도록 돕기 위해 고안되었습니다. 질문과 답변이 도움이되어야합니다. 아무도 이것에 의해 도움을 받고 있지 않습니다.
GoldenNewby

5
@ShadowWizard이 답변은 이미 많은 면책 조항과 왜 이것을 사용해서는 안되는지에 대해 이야기하는 사람들로 둘러싸여 있습니다. 나는 고의로 그 얼굴을 무시하는 사람들이 그렇게하는 결과에 직면하게하는 데 부끄러움을 느끼지 않습니다.
피터 올슨

8
@AlexMills의 경우 +1 솔직히, goto아마도 활용률이 낮을 것 같습니다. 아주 좋은 오류 처리 패턴을 만듭니다. 우리 switchgoto이름을 제외하고는 아랫배 통증이없는를 사용합니다.
0x1mason

122

아니요 . ECMAScript에는 포함되지 않았습니다.

ECMAScript에는 goto 문이 없습니다.


1
JavaScript를 디버깅하는 동안 GOTO가 유용한 지 궁금합니다. Afaik, IE만이 디버거에서 GOTO를 제공합니다 ... 실제로 유스 케이스를 찾았지만 일반적으로 유용 할 수 있는지 확실하지 않습니다 ... JavaScript를 디버깅하는 동안 뛰어 다니는 것이 좋습니다. 어떻게 생각해?
Šime Vidas

3
@ Šime Vidas : goto 기능을 사용한 디버깅이 유용한 지 잘 모르겠습니다. 기본적으로 당신은 어쨌든 디버깅하지 않고 결코 일어나지 않을 방식으로 코드 경로를 혼란스럽게 할 것입니다.
pimvdb

12
이 얼마나 유감 ... IMHO goto는 바보 같은 "기능"의 자바 스크립트 칵테일에 완벽하게 잘 맞을 것입니다 :)
Yuriy Nakonechnyy

4
goto그러나 나중에 사용하기 위해 예약 된 키워드입니다. 우리는 희망 만 있습니다 :)
Azmisov

4
goto중첩 함수에서 돌아 오려고 할 때 유용합니다. 예를 들어 underscore.js를 사용하는 경우 배열을 반복 할 때 익명 함수를 제공합니다. 그런 함수 안에서 돌아올 수 없으므로 goto end;유용합니다.
Hubro

31

실제로 ECMAScript (JavaScript)에 실제로는 문이 있습니다. 그러나 JavaScript goto에는 두 가지 맛이 있습니다!

goto의 두 가지 JavaScript 맛을 continue라고 표시하고 break라고 표시합니다. JavaScript에는 키워드 "goto"가 없습니다. goto는 break 및 continue 키워드를 사용하여 JavaScript로 수행됩니다.

그리고 이것은 w3schools 웹 사이트 http://www.w3schools.com/js/js_switch.asp 에 다소 명시 적으로 언급되어 있습니다 .

레이블이 붙은 계속 문서와 레이블 구분이 다소 어색하게 표현 된 것을 발견했습니다.

레이블 된 continue와 레이블 된 break의 차이점은 사용할 수있는 위치입니다. 레이블이있는 continue는 while 루프 내에서만 사용할 수 있습니다. 자세한 내용은 w3schools를 참조하십시오.

===========

작동하는 또 다른 접근법은 내부에 거대한 스위치 문이있는 거대한 while 문을 갖는 것입니다.

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
"표시된 continue는 while 루프 내에서만 사용할 수 있습니다." -아니오, 라벨이 붙어 break있으며 루프에도 continue사용될 수 있습니다 for. 그러나 그들은 정말이야 하지 동등 goto비교가, 관련 루프 (들)의 구조로 고정되어 주어진 goto그것을 가지고 언어 - - 어느 곳으로 이동하는 물론 수 있습니다.
nnnnnn

31

클래식 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에 넣어 어떤 목적으로 백엔드를 시뮬레이션해야합니다.

자바 스크립트 스타일 :

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 대신 루프를 사용할 수 있습니다.


1
continueA의 do ... while루프를 계속 체크 조건 . 따라서 뒤로 goto사용하면 do ... while (0)작동하지 않습니다. ecma-international.org/ecma-262/5.1/#sec-12.6.1
ZachB

1
작동하지 않습니다. 나는에이 let doLoop일이합니다. 그리고 주요 루프 : let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop) github.com/patarapolw/HanziLevelUp/blob/…
Polv

15

이것은 오래된 질문이지만 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 다음에 오므로 D 뒤에 A를 추가합니다 goto label3.

 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와 같은 매크로 시스템으로 수행 할 수 있습니다.


"적절한 테일 콜을 지원하는 구현에서 ES6에서 가능합니다". 모든 주요 브라우저에서 AFAIK 테일 통화가 비활성화됩니다.
JD

Safari는 적절한 꼬리 호출을 지원합니다. 답변을 받았을 때 명령 줄 스위치를 통해 Chrome에서 적절한 테일 콜을 활성화 할 수있었습니다. 그들이 다시 생각하기를 바랍니다-또는 적어도 명시 적으로 표시된 꼬리 호출을 지원하기 시작합니다.
soegaard

명시 적으로 표시된 꼬리 호출은 아마도 모든 사람을 행복하게 할 것입니다.
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

방법에 대한 for루프? 원하는만큼 반복하십시오. 또는 while루프, 조건이 충족 될 때까지 반복하십시오. 코드를 반복 할 수있는 제어 구조가 있습니다. 나는 GOTOBasic에서 기억합니다 ... 그런 나쁜 코드를 만들었습니다! 최신 프로그래밍 언어는 실제로 유지 관리 할 수있는 더 나은 옵션을 제공합니다.


무한 생산 루프 : 프로토 타입, 스크래치, 더 나은 프로토 타입, 스크래치, 더 나은 프로토 타입, 스크래치. 유지 관리는 종종 오류입니다. 많은 코드를 유지 관리 할 필요가 없습니다. 대부분의 코드는 유지 보수되지 않고 재 작성됩니다.
Pacerier

7

이를 수행 할 수있는 방법이 있지만 신중하게 계획해야합니다. 예를 들어 다음 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.

@ JonHarrop JavaScript가 스택 오버플로 전에 처리 할 수있는 최대 스택 크기가 있습니까?
Eliseo d' Annunzio

1
예, 매우 작은 것 같습니다. 내가 사용한 다른 어떤 언어보다 훨씬 작습니다.
JD

7

일반적으로 가독성을 높이기 위해 GoTo를 사용하지 않는 것이 좋습니다. 나에게 재귀 함수를 프로그래밍하는 대신 간단한 반복 함수를 프로그래밍하거나 스택 오버플로와 같은 것이 더 좋을 때 더 나은 (스택 오버플로와 같은 것이 두려워하는 경우) 실제 반복 대안 (때로는 복잡 할 수 있음)을 프로그래밍하는 것은 나쁜 변명입니다.

이와 같은 일이 있습니다.

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

바로 무한 루프가 있습니다. while 절의 paranthese에있는 표현식 ( "true")은 Javascript 엔진이 확인하는 것입니다. 표현식이 true이면 루프가 계속 실행됩니다. 여기에 "true"라고 쓰면 항상 true로 평가되므로 무한 루프입니다.


7

물론, switch구문을 사용하면 gotoJavaScript로 시뮬레이션 할 수 있습니다 . 불행히도, 언어는을 제공하지 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
  }
}

5

당신은 아마이 같은 일부 JS 튜토리얼 읽어야 하나 .

gotoJS에 존재 하는지 확실하지 않지만 어느 쪽이든 나쁜 코딩 스타일을 장려하므로 피해야합니다.

당신은 할 수 있습니다 :

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

4

함수를 간단하게 사용할 수 있습니다.

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

5
시스템에 메모리가 부족해질 때까지 호출 스택에서 반송 주소를 계속 밀어 넣기 때문에 이것은 매우 나쁜 생각입니다.
Paul Hutchinson

1
그러나 실제로 사용자는 끝없는 모달 RINSE-LATHER 대화에서 CTRL-ALT-DELETEd를 가질 것입니다!
Shayne

4

콜 스택을 깨끗하게 유지하면서 고토와 같은 기능을 달성하기 위해이 방법을 사용하고 있습니다.

// 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, 비동기 / 대기 지원이없는 환경에서 병렬화 할 수없는 루프를 일시 중지해야하지 않는 한이 방법이 필요한 경우가 발생하지 않아야합니다.


1
추잡한. 나는 그것을 좋아한다. FWIW, 그 기술을 트램폴린이라고합니다.
JD

이 작동하는지 확인할 수 있습니다. 함수 호출로 구현 될 때 깊은 재귀를 유발하는 GTO 문으로 일부 HP RPN을 수동으로 변환하고 있습니다. 위에 표시된 setTimeout () 메소드는 스택을 축소하고 재귀는 더 이상 문제가되지 않습니다. 그러나 훨씬 느립니다. 아, Node.js 에서이 작업을 수행하고 있습니다.
Jeff Lowery

3

모든 부모 폐쇄의 시작과 끝

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

이를 달성하는 또 다른 대안은 테일 콜을 사용하는 것입니다. 그러나 JavaScript에는 이와 같은 것이 없습니다. 따라서 일반적으로 goto는 아래 두 키워드를 사용하여 JS에서 수행됩니다. break and continue , 참조 : JavaScript의 Goto 문

예를 들면 다음과 같습니다.

var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.