Warum wird 'for (var item in list)' mit Arrays in JavaScript als schlechte Praxis angesehen?

78

Bei einem einfachen, auf Null basierenden, numerisch indizierten Array:

var list = ['Foo', 'Bar', 'Baz'];

Ich habe oft bemerkt, dass, wenn jemand vorschlägt, Variablen in einem Array wie diesem zu durchlaufen:

for(var item in list) { ... }

... gibt es mit ziemlicher Sicherheit jemanden, der dies für eine schlechte Praxis hält und einen alternativen Ansatz vorschlägt:

var count = list.length;

for(var i = 0; i < count; i++) {
    var item = list[i];
    ...
}

Was ist der Grund dafür, die einfachere Version oben nicht zu verwenden und stattdessen das zweite Beispiel zu verwenden?

Tatu Ulmanen
quelle
Sie durchlaufen nicht die Elemente mit dieser Schleife, sondern die Schlüssel / Eigenschaftsnamen / Indizes.
Bergi
5
Auch C-Codierer in viktorianischen Tophaten verstehen Iiteratoren nicht. Denken Sie jedoch daran, dass es sich um Schlüssel handelt, nicht um Werte. Das for (;;) - Format ist schneller, aber in 99% der Fälle spielt es keine Rolle. Die Programmierzeit ist teurer als die Rechenzeit, es sei denn, Sie arbeiten an Megaprojekten oder Dingen, die wirklich optimiert werden müssen.
Shayne

Antworten:

96

Erstens ist die Reihenfolge der Schleife für eine for...inSchleife undefiniert , sodass nicht garantiert werden kann, dass die Eigenschaften in der gewünschten Reihenfolge wiederholt werden.

Zweitens werden for...inalle aufzählbaren Eigenschaften eines Objekts durchlaufen, einschließlich der von seinem Prototyp geerbten. Im Fall von Arrays kann dies Auswirkungen auf Sie haben, wenn Ihr Code oder eine auf Ihrer Seite enthaltene Bibliothek den Prototyp von erweitert hat. Dies Arraykann sehr nützlich sein:

Array.prototype.remove = function(val) {
    // Irrelevant implementation details
};

var a = ["a", "b", "c"];

for (var i in a) {
    console.log(i);
}

// Logs 0, 1, 2, "remove" (though not necessarily in that order)
Tim Down
quelle
2
das ist in Ordnung, solange Sie verwenden hasOwnProperty- for (var i in a) { if (a.hasOwnProperty(i)) console.log(i); }-> 1 2 3
Dimitar Christoff
11
Ein Vorschlag, ändern Sie over all propertieszu over **enumerable** properties. In neueren Javascript-Implementierungen können Eigenschaften mit dem enumerableAttribut definiert werden false. Diese Eigenschaften und Eigenschaften von integrierten Javascript-Objekten werden in a nicht angezeigt for...in.
Andy E
4
@ Dimitar: In der Tat, obwohl die Schleife, sobald Sie sie hinzugefügt haben, nicht mehr einfacher aussieht als eine Standard-C-Schleife.
Tim Down
1
Wie auch immer - der einzige legitime Grund für das Schleifen eines solchen Arrays besteht darin, die Array-Schlüssel zu erhalten (was aufgrund der Art der Arrays in Javscript funktioniert) - aus jedem anderen Grund sollten Sie eine normale Schleife durchführen.
Dimitar Christoff
19

Geschwindigkeit?

for(..;..;..)Die Schleife erwies sich als 36-mal schneller als for .. in beim Testen hier.

Link mit freundlicher Genehmigung dieser SO-Antwort

Amarghosh
quelle
5
Ich habe das falsch verstanden, da die Endlosschleife 36x schneller ist als eine normale Schleife. Danke für den Link +1.
Thomas O
@ Thomas Vernünftiges Missverständnis - wenn aus dem Zusammenhang gelesen.
Behoben
1

Wenn Sie für / in so verwenden, itemwerden die Zeichenfolgenwerte "0", "1", ... aufgelistet, also nicht die tatsächlichen Objekte in der Liste. Das 'Element' im ersten Snippet ähnelt also eher dem iim zweiten Snippet, nicht dem item. Außerdem werden Zeichenfolgenwerte dort aufgelistet, wo Sie Zahlen erwarten würden. Und Sie bekommen Probleme, wenn Sie Eigenschaften in die Liste aufnehmen, wie array.ID = "a123"sie auch aufgezählt werden.

Aber mit diesen Nachteilen denke ich immer noch, dass die Syntax sehr nützlich ist, wenn Ihr Team weiß, was es tut.


quelle
1

for ... in ... Gibt keine Listenelemente zurück, sondern listet die Array-Eigenschaften auf.

Allein aus diesem Grund kann es nicht als Ersatz für eine for (i=0; i<arr.length; i++)Schleife dienen.

Die geeignete Alternative ist for ... of ...Konstrukt. Es listet Werte eines iterierbaren Objekts auf, z. B. eines Arrays. Weitere Informationen finden Sie in den MDN-Webdokumenten: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

Es wird von den relevanten modernen Browsern unterstützt (Internet Explorer zählt nicht und wird durch Microsoft Edge ersetzt). Wenn Sie es sich leisten können, ältere Browser nicht zu unterstützen, ist dies wahrscheinlich der richtige Weg. Sie können die praktische Browser-Support-Tabelle am Ende der oben genannten MDN-Seite überprüfen, um festzustellen, welche Browserversionen tatsächlich die for ... of ...Verwendung zulassen .

Alice
quelle
Ich würde mich sehr freuen zu wissen, dass Ihre Behauptung über IE wahr und vertrauenswürdig sein könnte :)
CapelliC
0

Fügen Sie hinzu list.foo = bar;und versuchen Sie, einfach zu verwenden for. Wenn Sie einige Bibliotheken (wie prototypeJs) nicht verwenden und dem Array-Objekt keine neuen Eigenschaften hinzufügen, können Sie eine einfache for-Anweisung verwenden.

Selbst
quelle