Man hat mir gesagt, for...in
nicht mit Arrays in JavaScript zu verwenden. Warum nicht?
Sie können das Präfix +
anstelle von parseInt
verwenden, es sei denn, Sie benötigen wirklich Ganzzahlen oder ignorieren ungültige Zeichen.
Man hat mir gesagt, for...in
nicht mit Arrays in JavaScript zu verwenden. Warum nicht?
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...
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.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.
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.
``
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.
`
Sie können das Präfix +
anstelle von parseInt
verwenden, es sei denn, Sie benötigen wirklich Ganzzahlen oder ignorieren ungültige Zeichen.
Außerdem wird nicht empfohlen, parseInt()
zu verwenden. Versuche parseInt("025");
und es wird fehlschlagen.
@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.
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.
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.
Object.keys(a).forEach( function(item) { console.log(item) } )
iteriert über ein Array eigener Eigenschaftsschlüssel, nicht über solche, die vom Prototyp geerbt wurden.
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.
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 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.
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?
1 Stimmen
@MattDiPasquale - Ja, es ist umgekehrt, jedoch unter einer bekannten Grenze ermöglicht es eine optimale Verarbeitung, insbesondere in älteren Browsern, durch Iteration über einen bekannten Satz im Gegensatz zu einer unbekannten Satzlänge, indem die Grenze zuerst festgelegt wird. Es ist die Natur einer interpretierten Sprache.
0 Stimmen
@MarkSchultheiss Guter Kommentar. Man könnte die
for
-Schleife auch alsfor (var i = hColl.length; i--;) {}
schreiben, was ein ähnliches Leistungsprofil wie die umgekehrtewhile
-Schleife haben sollte.5 Stimmen
@Wynand verwenden Sie
var i = hCol1.length; for (i;i;i--;) {}
speichern Sie das i im Cache, da es einen Unterschied macht und den Test vereinfacht. - je älter der Browser, desto größer der Unterschied zwischenfor
undwhile
IMMER den "i" Zähler im Cache speichern - und natürlich passt negativ nicht immer zur Situation und das Negative, währendobfuscate
den Code für einige Leute ein wenig verkompliziert. und beachten Sievar i = 1000; for (i; i; i--) {}
undvar b =1000 for (b; b--;) {}
wobei i von 1000 auf 1 und b von 999 auf 0 geht. - je älter der Browser, desto mehr neigt das while zur Leistungssteigerung.12 Stimmen
Sie können auch klug sein.
for(var i = 0, l = myArray.length; i < l; ++i) ...
ist die schnellste und beste Möglichkeit, die Sie mit einem Vorwärtsdurchlauf erhalten können.0 Stimmen
Es ist jetzt 10 Jahre später und ich verspüre den Drang hinzuzufügen: Auch wenn diese Optimierungen den Code leicht schneller machen: es sind Mikro-Optimierungen. Wenn Sie sich unsicher sind, entscheiden Sie sich für lesbaren Code, nicht für eine stark optimierte Schleife über ein Array mit 1000 Elementen. Wenn etwas langsam ist, dann ist es normalerweise der Code, der innerhalb der Schleife ausgeführt wird, nicht die Schleifensteuerung.