Javascript'te goto'yu nasıl kullanabilirim?


127

Kesinlikle kullanmam gereken bazı kodlar var goto. Örneğin şöyle bir program yazmak istiyorum:

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

Bunu Javascript'te yapmanın bir yolu var mı?


goto, derlenmiş javascript için ikna edici olacaktır. JavaScript ile yazılmış bir JVM'im var. Goto ifadesiyle çok daha başarılı ve daha kısa olacaktır.
neoexpert

Yanıtlar:


151

Kesinlikle! JavaScript'i tam potansiyelinde kullanmanıza izin veren ve kodunuzu yazma şeklinizde devrim yaratacak Summer of Goto adlı bir proje var .

Bu JavaScript ön işleme aracı, bir etiket oluşturmanıza ve ardından bu sözdizimini kullanarak ona gitmenize olanak tanır:

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

Örneğin sorudaki örnek şu şekilde yazılabilir:

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

Sonsuz bir LATHER RINSEtekrar döngüsü gibi basit önemsiz programlarla sınırlı olmadığınızı unutmayın - sağladığı olanaklar gotosonsuzdur ve hatta Hello, world!şu şekilde JavaScript konsoluna 538 kez mesaj gönderebilirsiniz:

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

Goto'nun nasıl uygulandığı hakkında daha fazla bilgi edinebilirsiniz , ancak temelde, etiketli bir whiledöngü ile bir goto simülasyonu yapabileceğiniz gerçeğinden yararlanan bazı JavaScript ön işlemleri yapar . Öyleyse, "Merhaba dünya!" yukarıdaki program, aşağıdaki gibi bir şeye çevrilir:

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

Bu ön işleme sürecinde bazı sınırlamalar vardır, çünkü while döngüleri birden fazla işlev veya bloğa yayılamaz. Yine de bu önemli bir şey değil goto- JavaScript'ten yararlanmanın faydalarının sizi kesinlikle bunaltacağına eminim.

Goto.js kitaplığına götüren yukarıdaki bağlantıların tümü TAMAMEN ÖLÜ, işte gerekli bağlantılar:

goto.js (sıkıştırılmamış) --- parseScripts.js (sıkıştırılmamış)

Gönderen Goto.js :

Not: Merak eden herkes için (şimdiye kadar toplam sıfır kişi), Summer of Goto, bu senaryoyu ve PHP'nin dillerine goto ekleme kararını tartışırken Paul Irish tarafından popüler hale getirilen bir terimdir.

Ve tüm bu şeyin bir şaka olduğunu hemen anlamayanlar için lütfen beni affet. <- (sigorta).


10
@SurrealDreams Bir şaka olabilir ama aslında işe yarıyor. JsFiddle bağlantılarına tıklayabilir ve gerçekten çalıştıklarını görebilirsiniz.
Peter Olson


6
@PeterOlson, Ancak stackoverflow, insanların programlamayı öğrenmelerine yardımcı olmayı amaçlamaktadır. Sorular ve cevaplar bunu yapmak için faydalı olmalıdır. Bundan kimseye yardım edilmiyor.
GoldenNewby

5
@ShadowWizard Bu yanıt zaten birçok sorumluluk reddi beyanı ve bunun neden kullanılmaması gerektiği hakkında konuşan insanlarla çevrilidir. Bunu isteyerek görmezden gelen insanların, bunu yapmanın sonuçlarıyla yüzleşmesine izin vermekten utanmıyorum.
Peter Olson

8
@AlexMills için +1. Dürüst olmak gerekirse, gotomuhtemelen yetersiz kullanıldığını düşünüyorum . Bazı çok güzel hata işleme kalıpları sağlar. Heck, biz switch, gotoadı dışında her şeyi kullanıyoruz ve kimse karın ağrısı çekmiyor.
0x1mason

122

Hayır. Bunu ECMAScript'e dahil etmediler:

ECMAScript'in goto ifadesi yok.


1
JavaScript'te hata ayıklarken GOTO'nun yararlı olup olmayacağını merak ediyordum. Afaik, hata ayıklayıcısında yalnızca IE GOTO sağlar ... ve aslında bunun için bir kullanım durumu buldum, ancak JavaScript'te hata ayıklarken etrafta gezinmenin yararlı olup olamayacağından emin değilim. Ne düşünüyorsun?
Šime Vidas

3
@ Šime Vidas: Goto işleviyle hata ayıklamanın yararlı olup olmadığından emin değilim. Temel olarak, zaten hata ayıklamadan asla olmayacak bir şekilde kod yolu ile uğraşıyor olacaksınız.
pimvdb

12
Ne yazık ... IMHO goto, javascript'in aptal "özelliklerinden" oluşan kokteyline mükemmel bir şekilde uyuyor :)
Yuriy Nakonechnyy

4
gotoancak, ileride kullanılmak üzere ayrılmış bir anahtar kelimedir. Sadece umut edebiliriz :)
Azmisov

4
gotoiç içe geçmiş bir işlevden dönmek istediğinizde yararlı olacaktır. Örneğin, alt çizgi.js kullanırken, diziler üzerinde yineleme yaparken anonim bir işlev sağlarsınız. Böyle bir fonksiyonun içinden dönemezsiniz, bu yüzden goto end;faydalı olacaktır.
Hubro

31

Aslında, ECMAScript (JavaScript) DOES INDEED'in bir goto ifadesi olduğunu görüyorum. Ancak, JavaScript goto'nun iki çeşidi vardır!

Goto'nun iki JavaScript çeşidi, etiketli devam ve ara etiketli olarak adlandırılır. JavaScript'te "goto" anahtar kelimesi yoktur. Goto, JavaScript'te break ve continue anahtar sözcükleri kullanılarak gerçekleştirilir.

Ve bu, http://www.w3schools.com/js/js_switch.asp buradaki w3schools web sitesinde aşağı yukarı açıkça belirtilmiştir .

Devam et etiketli ve ara etiketli belgelerin biraz garip bir şekilde ifade edildiğini görüyorum.

Etiketli devam ve etiketli ara arasındaki fark, kullanılabilecekleri yerdir. Etiketli devam, yalnızca bir süre döngüsü içinde kullanılabilir. Daha fazla bilgi için w3schools'a bakın.

===========

İşe yarayacak başka bir yaklaşım, içinde dev bir anahtar ifadesi bulunan dev bir while ifadesine sahip olmaktır:

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
"Etiketli devam yalnızca bir while döngüsü içinde kullanılabilir." - Hayır, etiketli breakve döngülerde de continuekullanılabilir for. Ama gerçekten konum değil eşdeğer gotokıyasla bunlar, ilgili döngü (ler) in yapısına kilitlenmiş göz önüne alındığında gotoo var dilde - - her yerde gidip hangi elbette olabilir.
nnnnnn

31

Klasik JavaScript'te, bu tür bir kodu elde etmek için do-while döngüleri kullanmanız gerekir. Sanırım başka bir şey için kod üretiyorsunuz.

Bayt kodunu JavaScript'e arka plana göndermek gibi bunu yapmanın yolu, her etiket hedefini "etiketli" bir işle kaplamaktır.

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

Bu şekilde kullandığınız her etiketli do-while döngüsü aslında bir etiket için iki etiket noktası oluşturur. Biri en üstte ve diğeri döngünün sonunda. Geri atlamak devam eder ve ileri atlamak mola verir.

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

Maalesef bunu yapmanın başka yolu yok.

Normal Örnek Kod:

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

Diyelim ki kod bayt kodlarına kodlandı, bu yüzden şimdi arka ucunuzu bir amaç için simüle etmek için bayt kodlarını JavaScript'e koymalısınız.

JavaScript stili:

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)

Dolayısıyla, bu tekniği kullanmak işi basit amaçlar için iyi yapar. Bunun dışında yapabileceğin pek bir şey yok.

Normal Javacript için hiçbir zaman goto kullanmanıza gerek yoktur, bu nedenle JavaScript üzerinde çalıştırmak için başka stil kodunu özel olarak çevirmediğiniz sürece muhtemelen bu teknikten kaçınmalısınız. Örneğin, Linux çekirdeğini JavaScript'te başlatmak için böyle yaptıklarını varsayıyorum.

NOT! Bu tamamen saf bir açıklama. Bayt kodlarının uygun Js arka ucu için, kodu çıktılamadan önce döngüleri incelemeyi de düşünün. Birçok basit while döngüsü bu şekilde algılanabilir ve daha sonra goto yerine döngüleri kullanmayı tercih edebilirsiniz.


1
continuebir do ... whiledöngüde kontrol koşuluna devam eder . gotoBurada geriye doğru kullanmak do ... while (0)işe yaramaz. ecma-international.org/ecma-262/5.1/#sec-12.6.1
ZachB

1
Çalışmıyor. Bunun let doLoopişe yaraması için yapmalıyım . Ve ana döngü: let doLoop = false; do { if(condition){ doLoop = true; continue; } } while (doLoop) github.com/patarapolw/HanziLevelUp/blob/…
Polv

15

Bu eski bir sorudur, ancak JavaScript hareketli bir hedef olduğu için - doğru kuyruk çağrılarını destekleyen uygulamada ES6'da mümkündür. Uygun kuyruk çağrılarını destekleyen uygulamalarda, sınırsız sayıda aktif kuyruk çağrısına sahip olabilirsiniz (yani kuyruk çağrıları "yığını büyütmez").

A goto, parametresi olmayan bir kuyruk çağrısı olarak düşünülebilir.

Örnek:

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

olarak yazılabilir

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

Burada çağrı startkuyruk konumunda olduğundan yığın taşması olmayacaktır.

İşte daha karmaşık bir örnek:

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

Önce kaynağı bloklara ayırdık. Her etiket yeni bir bloğun başlangıcını gösterir.

 Block1
     label1:   A
               B
               if C goto label3
               D

  Block2    
     label3:   E
               goto label1

Gotos kullanarak blokları birbirine bağlamamız gerekiyor. Örnekte E bloğu D'yi takip eder, bu yüzden goto label3D'den sonra bir ekleriz .

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

  Block2    
     label2:   E
               goto label1

Artık her blok bir işlev haline gelir ve her gitme bir kuyruk çağrısı olur.

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

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

Programı başlatmak için kullanın label1().

Yeniden yazma tamamen mekaniktir ve bu nedenle gerekirse sweet.js gibi bir makro sistemle yapılabilir.


"Doğru kuyruk çağrılarını destekleyen uygulamada ES6'da mümkündür". AFAIK kuyruk çağrıları tüm büyük tarayıcılarda devre dışı bırakılmıştır.
JD

Safari uygun kuyruk aramalarını destekliyor sanırım. Cevabın verildiği sırada, Chrome'da bir komut satırı anahtarı aracılığıyla uygun kuyruk çağrılarını etkinleştirmek mümkündü. Umarım yeniden düşünürler - veya en azından açıkça işaretlenmiş kuyruk aramalarını desteklemeye başlarlar.
soegaard

Açıkça işaretlenmiş kuyruk aramaları muhtemelen herkesi mutlu edecektir.
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

Bir fordöngü nasıl olur ? İstediğiniz kadar tekrarlayın. Veya bir whiledöngü, bir koşul karşılanana kadar tekrarlayın. Kodu tekrarlamanıza izin verecek kontrol yapıları vardır. Temelde hatırlıyorum GOTO... çok kötü bir kod yaptı! Modern programlama dilleri, gerçekten koruyabileceğiniz daha iyi seçenekler sunar.


Sonsuz üretim döngüsü: Prototip, çizik, daha iyi prototip, çizik, daha iyi prototip, çizik. Bakım genellikle bir hatadır. Çok fazla kodun korunmasına gerek yoktur. Çoğu kod yeniden yazılır, korunmaz.
Pacerier

7

Bunu yapmanın bir yolu var ama dikkatlice planlanması gerekiyor. Örneğin aşağıdaki QBASIC programını ele alalım:

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

Ardından, önce tüm değişkenleri başlatmak için JavaScript'inizi oluşturun, ardından topun yuvarlanmasını başlatmak için bir ilk işlev çağrısı yapın (bu ilk işlev çağrısını sonunda yürütürüz) ve içinde çalıştırılacağını bildiğiniz her satır kümesi için işlevleri ayarlayın. tek birim.

Bunu ilk işlev çağrısıyla takip edin ...

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

Bu durumda sonuç şudur:

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'in taşmadan önce işleyebileceği maksimum yığın boyutu var mı?
Eliseo d'Annunzio

1
Evet ve çok küçük görünüyor. Şimdiye kadar kullandığım diğer dillerden çok daha küçük.
JD

7

Genel olarak, kötü okunabilirlik için GoTo'yu kullanmamayı tercih ederim. Bana göre bu, özyinelemeli işlevleri programlamak yerine basit yinelemeli işlevleri programlamak için kötü bir bahane veya daha da iyisi (Yığın Taşması gibi şeylerden korkuluyorsa), gerçek yinelemeli alternatifleri (bazen karmaşık olabilir).

Bunun gibi bir şey yapardı:

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

İşte sonsuz bir döngü var. While cümlesinin parantezleri içindeki ifade ("true"), Javascript motorunun kontrol edeceği şeydir - ve eğer ifade doğruysa, döngünün çalışmasını sağlar. Burada "doğru" yazmak her zaman doğru olarak değerlendirilir, dolayısıyla sonsuz bir döngüdür.


7

Elbette, switchyapıyı kullanarak gotoJavaScript'te simüle edebilirsiniz . Maalesef dil sağlamıyor goto, ancak bu yeterince iyi bir ikame.

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

Muhtemelen bu gibi bazı JS öğreticiler okumalı biri .

gotoJS'de var olup olmadığından emin değilim , ancak her iki durumda da kötü kodlama stilini teşvik eder ve bundan kaçınılmalıdır.

Yapabilirsin:

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

4

Bir işlevi basitçe kullanabilirsiniz:

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

5
Bu gerçekten kötü bir fikir çünkü sistem belleği bitene kadar çağrı yığınındaki dönüş adresini zorlamaya devam edecek.
Paul Hutchinson

1
Gerçekte, kullanıcı, sonsuz modal DURULAMA-LATHER diyaloglarından çok daha önce CTRL-ALT-DELETEd'e sahip olacaktır!
Shayne

4

Çağrı yığınını temiz tutarken goto benzeri işlevsellik elde etmek için şu yöntemi kullanıyorum:

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

// ...

Lütfen, işlev çağrıları tarayıcının güncelleme döngüsünde daha sonra değerlendirilecek olan zaman aşımı kuyruğuna eklendiğinden bu kodun yavaş olduğunu unutmayın.

Lütfen bağımsız değişkenleri iletebileceğinizi de unutmayın ( setTimeout(func, 0, arg1, args...)IE9'dan daha yeni tarayıcılarda veya setTimeout(function(){func(arg1, args...)}, 0)eski tarayıcılarda kullanarak.

AFAIK, asenkron / bekleme desteği olmayan bir ortamda paralel olmayan bir döngüyü duraklatmanız gerekmedikçe, bu yöntemi gerektiren bir vakayla asla karşılaşmamalısınız.


1
Pis. Onu seviyorum. FWIW, bu tekniğe tramplen denir.
JD

Bunun çalıştığını doğrulayabilirim. İşlev çağrıları olarak uygulandığında derin özyinelemeye yol açan GTO ifadeleriyle bazı HP RPN'yi manuel olarak aktarıyorum; yukarıda gösterilen setTimeout () yöntemi yığını daraltır ve özyineleme artık bir sorun değildir. Ama çok daha yavaştır. Oh, ve bunu Node.js'de yapıyorum.
Jeff Lowery

3

tüm ebeveynlerin kapatmalarının başlangıcına ve sonuna git

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

Aynı şeyi başarmanın bir başka alternatif yolu da kuyruk aramalarını kullanmaktır. Ancak JavaScript'te böyle bir şey yok. Genel olarak, goto, aşağıdaki iki anahtar kelime kullanılarak JS'de gerçekleştirilir. break ve Continue , başvuru: JavaScript'te Goto İfadesi

İşte bir örnek:

var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.