Welches der beiden folgenden Codefragmente (oder keines / beide) sollte in einer vollständigen Implementierung von ECMAScript 2015 funktionieren:

for (const e of a)

for (const i = 0; i < a.length; i += 1)

Nach meinem Verständnis sollte das erste Beispiel funktionieren, da e für jede Iteration initialisiert wird. Sollte dies nicht auch für i in der zweiten Version der Fall sein?

Ich bin verwirrt, weil vorhandene Implementierungen (Babel, IE, Firefox, Chrome, ESLint) nicht konsistent zu sein scheinen und eine vollständige Implementierung von const mit verschiedenen Verhaltensweisen der beiden Schleifenvarianten aufweisen. Ich bin auch nicht in der Lage, einen konkreten Punkt im Standard zu finden, daher wäre das sehr dankbar.

90
adrianp 13 Aug. 2015 im 14:52

3 Antworten

Beste Antwort

Die folgende for-of-Schleife funktioniert:

for (const e of a)

Die ES6-Spezifikation beschreibt dies wie folgt:

ForDeclaration: LetOrConst ForBinding

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-in-and-for-of-statements-static-semantics-boundnames

Der Imperativ für die Schleife funktioniert nicht:

for (const i = 0; i < a.length; i += 1)

Dies liegt daran, dass die Deklaration nur einmal ausgewertet wird, bevor der Schleifenkörper ausgeführt wird.

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-statement-runtime-semantics-labelledevaluation

87
lyschoening 13 Aug. 2015 im 13:58

Ich werde die Spezifikation diesmal nicht zitieren, weil ich denke, dass es einfacher ist zu verstehen, was anhand eines Beispiels passiert.

for (const e of a) …

Ist im Grunde gleichbedeutend mit

{
    const __it = a[Symbol.iterator]();
    let __res;
    while ((__res = __it.next()) && !__res.done) {
        const e = __res.value;
        …
    }
}

Der Einfachheit halber habe ich ignoriert, dass es eine TDZ mit e für den Ausdruck a und die verschiedenen __it.return() / __it.throw(e) -Aufrufe gibt, falls die Schleife vorzeitig beendet wird ({{ X4}} oder throw im Körper).

for (const i = 0; i < a.length; i += 1) …

Ist im Grunde gleichbedeutend mit

{
    const i = 0;
    while (i < a.length) {
        …
        i += 1;
    }
}

Im Gegensatz zu let funktioniert eine const -Deklaration in einer for -Schleife nicht werden in jeder Schleifeniteration neu deklariert (und der Initialisierer wird sowieso nicht erneut ausgeführt). Sofern Sie nicht break in der ersten Iteration sind, wird Ihr i += hierher werfen.

40
Bergi 19 Apr. 2019 im 15:10

Ihr zweites Beispiel sollte definitiv nicht funktionieren, da i einmal deklariert wird und nicht bei jeder Iteration. Dies ist nur eine Funktion der Funktionsweise dieser Kategorie von Schleifen.

Sie können dies in einem normalen Browser versuchen:

for (var i = 0, otherVar = ""; i < [1,2,3,4].length; i += 1){
  console.log(otherVar)
  otherVar = "If otherVar was initialized on each iteration, then you would never read me.";
}

Es ist nicht der Fall, dass const in for Schleifen nicht zulässig ist. Nur for, das const ändert, ist.

Diese sind gültig:

for(const i = 0;;){ break } 
for(const i = 0; i < 10;){ break; } 

Diese sind ungültig:

for(const i = 0;;){ ++i; break; } 
for(const i = 0;;++i){ if(i > 0) break; }

Ich bin mir nicht sicher, warum Firefox nach dem Lesen der ES2015-Spezifikation einen SyntaxError ausgibt (obwohl ich sicher bin, dass die cleveren Leute bei Mozilla korrekt sind), es scheint, als sollte dies eine Ausnahme auslösen:

Erstellen Sie eine neue, aber nicht initialisierte unveränderliche Bindung in einem Umgebungsdatensatz. Der String-Wert N ist der Text des gebundenen Namens. Wenn S true ist, löst der Versuch, auf den Wert der Bindung vor der Initialisierung zuzugreifen oder ihn nach der Initialisierung festzulegen, immer eine Ausnahme aus, unabhängig von der strengen Moduseinstellung der Operationen, die auf diese Bindung verweisen. S ist ein optionaler Parameter, der standardmäßig false ist.

3
Kit Sunde 14 Aug. 2015 im 09:21