2083 Stimmen

Warum ist es eine schlechte Idee, "for...in" zur Iteration von Arrays zu verwenden?

Man hat mir gesagt, for...in nicht mit Arrays in JavaScript zu verwenden. Warum nicht?

54 Stimmen

Ich habe die kürzliche Frage gesehen, in der jemand das zu dir gesagt hat, aber sie meinten nur für Arrays. Es wird als schlechte Praxis betrachtet, durch Arrays zu iterieren, aber nicht unbedingt für die Iteration durch Elemente eines Objekts.

22 Stimmen

Viele Antworten mit "for"-Schleifen wie 'for (var i=0; i

3 Stimmen

@MarkSchultheiss aber das ist eine Rückwärtsiteration. Gibt es eine andere Version der Vorwärtsiteration, die schneller ist?

46voto

WynandB Punkte 1317

Kurze Antwort: Es lohnt sich einfach nicht.


Längere Antwort: Es lohnt sich einfach nicht, auch wenn die Reihenfolge der Elemente und optimale Leistung nicht erforderlich sind.


Lange Antwort: Es lohnt sich einfach nicht...

  • Die Verwendung von for (var property in array) führt dazu, dass array als ein Objekt durchlaufen wird, wodurch die Objekt-Prototypenkette durchlaufen wird und letztendlich langsamer als eine indexbasierte for-Schleife ausgeführt wird.
  • for (... in ...) gibt die Objekteigenschaften nicht in sequenzieller Reihenfolge zurück, wie man es erwarten würde.
  • Die Verwendung von hasOwnProperty() und !isNaN() zur Filterung der Objekteigenschaften ist ein zusätzlicher Overhead, der dazu führt, dass die Leistung noch langsamer wird und den Hauptgrund für die Verwendung zunichte macht, d. h. aufgrund des kürzeren Formats.

Aus diesen Gründen existiert kein akzeptabler Kompromiss zwischen Leistung und Bequemlichkeit. Es gibt wirklich keinen Nutzen, es sei denn, die Absicht besteht darin, das Array als ein Objekt zu behandeln und Operationen auf den Objekteigenschaften des Arrays durchzuführen.

41voto

JacquesB Punkte 40790

In Isolation ist nichts falsch daran, for-in bei Arrays zu verwenden. For-in iteriert über die Eigenschaftsnamen eines Objekts, und im Fall eines "Out-of-the-box"-Arrays entsprechen die Eigenschaften den Array-Indizes. (Die eingebauten Eigenschaften wie length, toString und so weiter sind nicht in der Iteration enthalten.)

Jedoch, wenn dein Code (oder das Framework, das du verwendest) benutzerdefinierte Eigenschaften zu Arrays oder zum Array-Prototyp hinzufügt, werden diese Eigenschaften in der Iteration enthalten sein, was wahrscheinlich nicht das ist, was du willst.

Einige JS-Frameworks, wie Prototype, modifizieren den Array-Prototyp. Andere Frameworks wie JQuery tun dies nicht, daher kannst du mit JQuery sicher for-in verwenden.

Wenn du unsicher bist, solltest du wahrscheinlich kein for-in verwenden.

Ein alternativer Weg, um durch ein Array zu iterieren, ist die Verwendung einer for-Schleife:

for (var ix=0;ix

``

Allerdings hat dies ein anderes Problem. Das Problem ist, dass ein JavaScript-Array "Löcher" haben kann. Wenn du arr wie folgt definierst:

var arr = ["hallo"];
arr[100] = "auf Wiedersehen";

Dann hat das Array zwei Elemente, aber eine Länge von 101. Die Verwendung von for-in liefert zwei Indizes, während die for-Schleife 101 Indizes liefert, wobei der 99. Index den Wert undefined hat.

``

35voto

ctmiddle Punkte 351

Zusätzlich zu den in anderen Antworten genannten Gründen möchten Sie möglicherweise die "for...in"-Struktur nicht verwenden, wenn Sie mit der Zählervariable mathematische Operationen durchführen müssen, da die Schleife durch die Namen der Objekteigenschaften iteriert und die Variable daher ein String ist.

Zum Beispiel,

for (var i=0; i

`

wird schreiben

0, number, 1
1, number, 2
...

während

for (var ii in a) {
    document.write(i + ', ' + typeof i + ', ' + i+1);
}

schreiben wird

0, string 01
1, string, 11
...

Natürlich kann dies leicht überwunden werden, indem man

ii = parseInt(ii);

in der Schleife hinzufügt, aber die erste Struktur ist direkter.

`

6 Stimmen

Sie können das Präfix + anstelle von parseInt verwenden, es sei denn, Sie benötigen wirklich Ganzzahlen oder ignorieren ungültige Zeichen.

0 Stimmen

Außerdem wird nicht empfohlen, parseInt() zu verwenden. Versuche parseInt("025"); und es wird fehlschlagen.

7 Stimmen

@Derek - Du kannst definitiv parseInt verwenden. Das Problem ist, wenn du das Radix nicht einschließt, könnten ältere Browser versuchen, die Nummer zu interpretieren (deshalb wird 025 zu oktal). Dies wurde in ECMAScript 5 behoben, aber es passiert immer noch bei Zahlen, die mit "0x" beginnen (es interpretiert die Nummer als hexadezimal). Um auf der sicheren Seite zu sein, verwende das Radix, um die Nummer wie folgt zu spezifizieren parseInt("025", 10) - das spezifiziert die Basis 10.

23voto

cHao Punkte 81921

Abgesehen davon, dass für...in Schleifen über alle zählbaren Eigenschaften iterieren (was nicht dasselbe ist wie "alle Array-Elemente"!), siehe http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf, Abschnitt 12.6.4 (5. Ausgabe) oder 13.7.5.15 (7. Ausgabe):

Die Mechanik und die Reihenfolge des Enumerierens der Eigenschaften ... ist nicht spezifiziert...

(Hervorhebung von mir.)

Dies bedeutet, dass ein Browser, wenn er wollte, die Eigenschaften in der Reihenfolge durchgehen könnte, in der sie eingefügt wurden. Oder in numerischer Reihenfolge. Oder in lexikographischer Reihenfolge (wo "30" vor "4" kommt! Beachten Sie, dass alle Objektschlüssel - und somit alle Array-Indizes - tatsächlich Zeichenfolgen sind, also macht das absolut Sinn). Er könnte sie nach Bucket durchlaufen, wenn er Objekte als Hashtabellen implementiert hätte. Oder das alles nehmen und "rückwärts" hinzufügen. Ein Browser könnte sogar zufällig durchlaufen und trotzdem ECMA-262 konform sein, solange er jede Eigenschaft genau einmal besucht.

In der Praxis tendieren die meisten Browser derzeit dazu, ungefähr in derselben Reihenfolge zu iterieren. Aber es gibt nichts, was besagt, dass sie es müssen. Das ist implementierungsspezifisch und könnte sich jederzeit ändern, wenn eine andere Methode gefunden wird, die wesentlich effizienter ist.

In jedem Fall trägt für...in keine Konnotation von Reihenfolge. Wenn Ihnen die Reihenfolge wichtig ist, seien Sie explizit und verwenden Sie eine reguläre für Schleife mit einem Index.

19voto

Lior Punkte 1571

Hauptsächlich zwei Gründe:

Eins

Wie andere schon gesagt haben, könnten Schlüssel zurückgegeben werden, die nicht in deinem Array sind oder die vom Prototyp geerbt wurden. Wenn also, sagen wir, eine Bibliothek eine Eigenschaft zu den Array- oder Object-Prototypen hinzufügt:

Array.prototype.someProperty = true

wirst du es als Teil jedes Arrays erhalten:

for(var item in [1,2,3]){
  console.log(item) // wird 1,2,3 loggen, aber auch "someProperty"
}

Dies könnte man mit der hasOwnProperty-Methode lösen:

var ary = [1,2,3];
for(var item in ary){
   if(ary.hasOwnProperty(item)){
      console.log(item) // wird nur 1,2,3 loggen
   }
}

aber das gilt auch für das Iterieren über jedes Objekt mit einer for-in-Schleife.

Zwei

Normalerweise ist die Reihenfolge der Elemente in einem Array wichtig, aber die for-in-Schleife wird nicht unbedingt in der richtigen Reihenfolge iterieren, das liegt daran, dass sie das Array als Objekt behandelt, was die Art und Weise ist, wie es in JS implementiert ist, und nicht als Array. Das scheint eine Kleinigkeit zu sein, aber es kann Anwendungen wirklich durcheinander bringen und ist schwer zu debuggen.

2 Stimmen

Object.keys(a).forEach( function(item) { console.log(item) } ) iteriert über ein Array eigener Eigenschaftsschlüssel, nicht über solche, die vom Prototyp geerbt wurden.

2 Stimmen

Ja, aber ähnlich wie die for-in-Schleife wird es nicht unbedingt in der richtigen Indexreihenfolge sein. Außerdem funktioniert es nicht in älteren Browsern, die ES5 nicht unterstützen.

0 Stimmen

Sie können den Browsern array.forEach beibringen, indem Sie bestimmten Code in Ihre Skripte einfügen. Siehe Polyfill developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X