Bagaimana saya bisa menggunakan goto di Javascript?

127

Saya memiliki beberapa kode yang harus saya terapkan untuk digunakan goto. Misalnya, saya ingin menulis program seperti ini:

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

Apakah ada cara untuk melakukannya di Javascript?

Peter Olson
sumber
goto akan menjadi conviniend untuk kompilasi javascript. Saya punya JVM yang ditulis dalam JavaScript. Akan jauh lebih banyak pemain dan lebih pendek dengan pernyataan goto.
neoexpert

Jawaban:

151

Benar! Ada sebuah proyek bernama Summer of Goto yang memungkinkan Anda menggunakan JavaScript pada potensi penuhnya dan akan merevolusi cara Anda dapat menulis kode Anda.

Alat preprocessing JavaScript ini memungkinkan Anda membuat label dan kemudian menggunakannya menggunakan sintaks ini:

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

Misalnya, contoh dalam pertanyaan dapat ditulis sebagai berikut:

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

Perhatikan bahwa Anda tidak hanya terbatas pada program sepele yang sederhana seperti LATHER RINSEsiklus berulang tanpa akhir — kemungkinan yang diberikan gototidak terbatas dan Anda bahkan dapat membuat Hello, world!pesan ke konsol JavaScript 538 kali, seperti ini:

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

Anda dapat membaca lebih lanjut tentang bagaimana goto diimplementasikan , tetapi pada dasarnya, ia melakukan beberapa preprocessing JavaScript yang memanfaatkan fakta bahwa Anda dapat mensimulasikan goto dengan loop berlabelwhile . Jadi, ketika Anda menulis "Halo, dunia!" program di atas, akan diterjemahkan ke sesuatu seperti ini:

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

Ada beberapa batasan untuk proses preprocessing ini, karena sementara loop tidak dapat membentang di beberapa fungsi atau blok. Tapi itu bukan masalah besar — ​​saya yakin manfaat bisa memanfaatkan gotoJavaScript akan benar-benar membuat Anda kewalahan.

Semua tautan di atas yang mengarah ke pustaka goto.js adalah SEMUA MATI, di sini ada tautan yang dibutuhkan:

goto.js (tidak terkompresi) --- parseScripts.js (tidak terkompresi)

Dari Goto.js :

PS Bagi siapa saja yang bertanya-tanya (sejauh ini nol orang), Summer of Goto adalah istilah yang dipopulerkan oleh Paul Irish, saat membahas skrip ini dan keputusan PHP untuk menambahkan goto ke dalam bahasa mereka.

Dan bagi mereka yang tidak segera menyadari bahwa semua ini adalah lelucon, tolong maafkan saya. <- (asuransi).

Peter Olson
sumber
10
@ SurrealDreams Ini mungkin lelucon, tetapi itu benar-benar berfungsi. Anda dapat mengklik tautan jsFiddle dan melihat bahwa itu benar-benar berfungsi.
Peter Olson
22
Artikel yang Anda
tautkan
6
@PeterOlson, Tapi stackoverflow dimaksudkan untuk membantu orang belajar pemrograman. Pertanyaan dan jawaban harus bermanfaat untuk melakukannya. Tidak ada yang terbantu dengan ini.
GoldenNewby
5
@ShadowWizard Jawaban ini sudah dikelilingi oleh banyak penafian dan orang-orang membicarakan mengapa ini tidak boleh digunakan. Saya tidak merasa malu membiarkan orang-orang yang dengan sengaja mengabaikan itu menghadapi konsekuensi dari melakukan hal itu.
Peter Olson
8
+1 untuk @AlexMills. Jujur, saya pikir gotomungkin kurang dimanfaatkan. Itu membuat beberapa pola penanganan kesalahan yang sangat bagus. Heck, kita gunakan switch, yang gotosemuanya kecuali nama, dan tidak ada yang sakit perut.
0x1mason
122

Tidak. Mereka tidak memasukkannya ke dalam ECMAScript:

ECMAScript tidak memiliki pernyataan goto.

pimvdb
sumber
1
Saya bertanya-tanya apakah GOTO akan berguna saat debugging JavaScript. Afaik, hanya IE yang menyediakan GOTO di debugger-nya ... dan saya benar-benar menemukan use-case untuk itu, tapi saya tidak yakin apakah itu bisa berguna secara umum ... untuk melompat-lompat saat debugging JavaScript. Bagaimana menurut anda?
Šime Vidas
3
@ Šime Vidas: Saya tidak yakin apakah debugging dengan fungsionalitas goto bermanfaat. Pada dasarnya Anda akan bermain-main dengan jalur kode dengan cara yang tidak akan pernah terjadi tanpa debugging.
pimvdb
12
Sayang sekali ... IMHO gotoakan cocok dengan koktail javascript dari "fitur" :) :)
Yuriy Nakonechnyy
4
gotoadalah kata kunci yang dipesan untuk penggunaan di masa mendatang. Kami hanya bisa berharap :)
Azmisov
4
gotoakan berguna saat Anda ingin kembali dari fungsi bersarang. Misalnya, saat menggunakan underscore.js, Anda memberikan fungsi anonim saat iterating over array. Anda tidak dapat kembali dari dalam fungsi seperti itu, jadi goto end;akan berguna
Hubro
31

Sebenarnya, saya melihat bahwa ECMAScript (JavaScript) TIDAK MENGGUNAKAN pernyataan goto. Namun, goto JavaScript memiliki dua rasa!

Dua rasa JavaScript dari goto disebut berlabel lanjut dan berlabel istirahat. Tidak ada kata kunci "goto" di JavaScript. Goto diselesaikan dalam JavaScript menggunakan istirahat dan melanjutkan kata kunci.

Dan ini kurang lebih secara eksplisit dinyatakan di situs web w3schools di sini http://www.w3schools.com/js/js_switch.asp .

Saya menemukan dokumentasi dari label berlabel terus dan label agak canggung diekspresikan.

Perbedaan antara terus berlabel dan istirahat berlabel adalah di mana mereka dapat digunakan. Berlanjut berlabel hanya dapat digunakan di dalam loop sementara. Lihat sekolah w3 untuk informasi lebih lanjut.

===========

Pendekatan lain yang akan bekerja adalah memiliki pernyataan sementara raksasa dengan pernyataan beralih raksasa di dalamnya:

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

}
Indinfer
sumber
9
"Lanjutkan berlabel hanya dapat digunakan di dalam loop sementara." - Tidak, berlabel breakdan continuedapat digunakan dalam forloop juga. Tapi mereka benar-benar tidak setara dengan gotomengingat bahwa mereka terkunci ke dalam struktur loop terkait, dibandingkan dengan gotoyang tentu saja - dalam bahasa yang memilikinya - pergi ke mana saja.
nnnnnn
31

Dalam JavaScript klasik, Anda perlu menggunakan loop do-while untuk mencapai jenis kode ini. Saya kira Anda mungkin menghasilkan kode untuk beberapa hal lain.

Cara untuk melakukannya, seperti mem-backend bytecode ke JavaScript adalah dengan membungkus setiap target label dengan do-while "berlabel".

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

Setiap loop do-while berlabel yang Anda gunakan seperti ini sebenarnya menciptakan dua titik label untuk satu label. Satu di bagian atas dan satu di ujung lingkaran. Melompat kembali menggunakan terus dan melompat maju menggunakan istirahat.

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

Sayangnya tidak ada cara lain untuk melakukannya.

Kode Contoh Normal:

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

Jadi katakanlah kode akan dikodekan ke bytecodes jadi sekarang Anda harus memasukkan bytecode ke dalam JavaScript untuk mensimulasikan backend Anda untuk beberapa tujuan.

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

Jadi menggunakan teknik ini melakukan pekerjaan dengan baik untuk tujuan sederhana. Selain itu tidak banyak lagi yang bisa Anda lakukan.

Untuk Javacript biasa Anda tidak perlu menggunakan goto, jadi Anda mungkin harus menghindari teknik ini di sini kecuali jika Anda secara spesifik menerjemahkan kode gaya lain untuk dijalankan di JavaScript. Saya berasumsi itu adalah bagaimana mereka membuat kernel Linux untuk boot dalam JavaScript misalnya.

CATATAN! Ini semua penjelasan yang naif. Untuk backend Js yang tepat dari bytecodes juga pertimbangkan memeriksa loop sebelum mengeluarkan kode. Banyak loop sederhana sementara dapat dideteksi seperti itu dan kemudian Anda bisa menggunakan loop bukan goto.

Scimonster
sumber
1
continuedalam satu do ... whilelingkaran berlanjut ke kondisi pemeriksaan . Mundur di gotosini menggunakan do ... while (0)demikian tidak bekerja. ecma-international.org/ecma-262/5.1/#sec-12.6.1
ZachB
1
Tidak bekerja Saya harus melakukan let doLoopini agar berhasil. Dan loop utama: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop) github.com/patarapolw/HanziLevelUp/blob/…
Polv
15

Ini adalah pertanyaan lama, tetapi karena JavaScript adalah target yang bergerak - dimungkinkan dalam ES6 pada implementasi yang mendukung panggilan ekor yang tepat. Pada implementasi dengan dukungan untuk panggilan ekor yang tepat, Anda dapat memiliki jumlah panggilan ekor aktif yang tidak terbatas (mis. Panggilan ekor tidak "menumbuhkan tumpukan").

SEBUAH goto dapat dianggap sebagai panggilan ekor tanpa parameter.

Contoh:

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

dapat ditulis sebagai

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

Di sini panggilan untuk startberada di posisi ekor, sehingga tidak akan ada tumpukan yang meluap.

Ini adalah contoh yang lebih kompleks:

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

Pertama, kami membagi sumber menjadi beberapa blok. Setiap label menunjukkan awal dari blok baru.

 Block1
     label1:   A
               B
               if C goto label3
               D

  Block2    
     label3:   E
               goto label1

Kita perlu mengikat blok bersama-sama menggunakan gotos. Dalam contoh, blok E mengikuti D, jadi kami menambahkan goto label3setelah D.

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

  Block2    
     label2:   E
               goto label1

Sekarang setiap blok menjadi fungsi dan setiap goto menjadi panggilan ekor.

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

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

Untuk memulai program, gunakan label1().

Penulisan ulang adalah murni mekanis dan dengan demikian dapat dilakukan dengan sistem makro seperti sweet.js jika perlu.

soegaard
sumber
"dimungkinkan dalam ES6 pada implementasi yang mendukung panggilan ekor yang tepat". Panggilan ekor AFAIK dinonaktifkan di semua browser utama.
JD
Safari mendukung panggilan ekor yang tepat, saya percaya. Pada saat jawaban diberikan, dimungkinkan untuk mengaktifkan panggilan ekor yang tepat di Chrome melalui sakelar baris perintah. Mari berharap mereka mempertimbangkan kembali - atau setidaknya mulai mendukung panggilan ekor yang ditandai secara eksplisit.
soegaard
Panggilan ekor yang ditandai secara eksplisit mungkin akan membuat semua orang bahagia.
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;
}
Henri Gourvest
sumber
8

Bagaimana dengan forloop? Ulangi sebanyak yang Anda suka. Atau satu whileloop, ulangi sampai suatu kondisi terpenuhi. Ada struktur kontrol yang memungkinkan Anda mengulangi kode. Saya ingat GOTOdi Basic ... itu membuat kode yang buruk! Bahasa pemrograman modern memberi Anda pilihan yang lebih baik yang sebenarnya bisa Anda pertahankan.

Mimpi nyata
sumber
Lingkaran produksi tanpa batas: Prototipe, awal, prototipe yang lebih baik, awal, prototipe yang lebih baik, awal. Pemeliharaan seringkali salah. Tidak banyak kode yang perlu dipertahankan. Sebagian besar kode ditulis ulang, tidak dikelola.
Pacerier
7

Ada cara yang bisa dilakukan, tetapi perlu direncanakan dengan hati-hati. Ambil contoh program QBASIC berikut:

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

Kemudian buat JavaScript Anda untuk menginisialisasi semua variabel terlebih dahulu, diikuti dengan membuat panggilan fungsi awal untuk memulai bola bergulir (kami menjalankan panggilan fungsi awal ini di akhir), dan mengatur fungsi untuk setiap rangkaian garis yang Anda tahu akan dieksekusi di satu unit.

Ikuti ini dengan panggilan fungsi awal ...

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

Hasilnya dalam hal ini adalah:

a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
Eliseo d'Annunzio
sumber
@ JonHarrop apakah ada ukuran stack maksimum yang dapat ditangani JavaScript sebelum stack overflow?
Eliseo d'Annunzio
1
Ya dan tampaknya sangat kecil. Jauh lebih kecil daripada bahasa lain yang pernah saya gunakan.
JD
7

Secara umum, saya lebih suka tidak menggunakan GoTo untuk keterbacaan yang buruk. Bagi saya, itu adalah alasan buruk untuk pemrograman fungsi iteratif sederhana daripada harus memprogram fungsi rekursif, atau bahkan lebih baik (jika hal-hal seperti Stack Overflow ditakuti), alternatif iteratif mereka yang sebenarnya (yang kadang-kadang mungkin rumit).

Sesuatu seperti ini akan dilakukan:

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

Itu benar ada loop tak terbatas. Ekspresi ("true") di dalam parantheses sementara sementara adalah apa yang akan diperiksa oleh mesin Javascript - dan jika ekspresi itu benar, itu akan membuat loop tetap berjalan. Menulis "benar" di sini selalu bernilai true, karenanya merupakan infinite loop.

Mathias Lykkegaard Lorenzen
sumber
7

Tentu, menggunakan switchkonstruk yang dapat Anda simulasikan gotodalam JavaScript. Sayangnya, bahasa tidak menyediakan goto, tetapi ini cukup baik sebagai pengganti.

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
  }
}
Konrad Borowski
sumber
5

Anda mungkin harus membaca beberapa tutorial JS seperti ini satu .

Tidak yakin apakah gotoada di JS sama sekali, tetapi, bagaimanapun, itu mendorong gaya pengkodean yang buruk dan harus dihindari.

Anda bisa melakukannya:

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

Anda dapat menggunakan fungsi:

function hello() {
    alert("RINSE");
    alert("LATHER");
    hello();
}
andlrc
sumber
5
Ini adalah ide yang sangat buruk karena akan terus mendorong alamat pengirim pada tumpukan panggilan sampai sistem kehabisan memori.
Paul Hutchinson
1
Namun demikian, pengguna akan memiliki CTRL-ALT-DELETEd jauh sebelum dari modal tanpa akhir dialog RINSE-LATHER!
Shayne
4

Untuk mencapai fungsionalitas seperti goto sambil menjaga tumpukan panggilan tetap bersih, saya menggunakan metode ini:

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

// ...

Harap perhatikan bahwa kode ini lambat karena panggilan fungsi ditambahkan ke antrean batas waktu, yang kemudian dievaluasi, dalam loop pembaruan browser.

Harap perhatikan juga bahwa Anda dapat memberikan argumen (menggunakan setTimeout(func, 0, arg1, args...)di browser yang lebih baru dari IE9, atau setTimeout(function(){func(arg1, args...)}, 0)di browser yang lebih lama.

AFAIK, Anda seharusnya tidak pernah menemukan kasus yang memerlukan metode ini kecuali jika Anda perlu menjeda loop yang tidak dapat diparalelkan dalam lingkungan tanpa dukungan async / menunggu.

pzmarzly
sumber
1
Menjijikan. Aku menyukainya. FWIW, teknik itu disebut trampolining.
JD
Saya dapat memverifikasi ini berfungsi. Saya secara manual mengubah beberapa HP RPN dengan pernyataan GTO yang mengarah pada rekursi yang dalam ketika diimplementasikan sebagai pemanggilan fungsi; metode setTimeout () yang ditunjukkan di atas meruntuhkan tumpukan dan rekursi tidak lagi menjadi masalah. Tapi itu jauh lebih lambat. Oh, dan saya melakukan ini di Node.js.
Jeff Lowery
3

mulai dan berakhir dari semua penutupan orang tua

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);
Tito100
sumber
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);
            }
        }

sumber
2

Cara alternatif lain untuk mencapai hal yang sama adalah dengan menggunakan panggilan ekor. Namun, kami tidak memiliki yang seperti itu di JavaScript. Jadi secara umum, goto diselesaikan di JS menggunakan dua kata kunci di bawah ini. istirahat dan lanjutkan , referensi: Pernyataan Goto dalam JavaScript

Berikut ini sebuah contoh:

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