Ich wurde darauf hingewiesen, dass ich in JavaScript for...in
nicht mit Arrays verwenden soll. Warum?
Denken Sie daran, (var x in a)
anstelle von (x in a)
zu verwenden - möchten keine globale Variable erstellen.
Ich wurde darauf hingewiesen, dass ich in JavaScript for...in
nicht mit Arrays verwenden soll. Warum?
Der Grund dafür ist, dass ein Konstrukt:
var a = []; // Erstellt ein neues leeres Array.
a[5] = 5; // Völlig legaler JavaScript-Code, der das Array neu dimensioniert.
for (var i = 0; i < a.length; i++) {
// Iteriert über numerische Indizes von 0 bis 5, wie von jedem erwartet wird.
console.log(a[i]);
}
/* Wird anzeigen:
undefined
undefined
undefined
undefined
undefined
5
*/
kann manchmal völlig anders sein als das andere:
var a = [];
a[5] = 5;
for (var x in a) {
// Zeigt nur den explizit gesetzten Index "5" an und ignoriert 0-4
console.log(x);
}
/* Wird anzeigen:
5
*/
Beachten Sie auch, dass JavaScript-Bibliotheken möglicherweise Dinge wie diese tun, die sich auf jedes von Ihnen erstellte Array auswirken können:
// Irgendwo tief in Ihrer JavaScript-Bibliothek...
Array.prototype.foo = 1;
// Jetzt haben Sie keine Ahnung, was der folgende Code tun wird.
var a = [1, 2, 3, 4, 5];
for (var x in a){
// Nun ist foo in JEDEM Array enthalten und
// wird hier als Wert von 'x' angezeigt.
console.log(x);
}
/* Wird anzeigen:
0
1
2
3
4
foo
*/
Denken Sie daran, (var x in a)
anstelle von (x in a)
zu verwenden - möchten keine globale Variable erstellen.
Das erste Problem ist nicht schlecht, sondern nur ein Unterschied in der Semantik. Das zweite Problem scheint mir ein Grund (neben den Konflikten zwischen Bibliotheken, die dasselbe tun) zu sein, weshalb das Ändern des Prototyps eines integrierten Datentyps schlecht ist, anstatt dass for..in schlecht ist.
@Stewart. Der 'Unterschied in der Semantik' ist tatsächlich ein Fehler in Javascript. Die fehlerhafte Semantik bedeutet, dass der Code nicht das tut, was du denkst, und deshalb wird die Konstruktion in der Regel vermieden.
Die for-in
-Anweisung an sich ist keine "schlechte Praxis", jedoch kann sie falsch verwendet werden, zum Beispiel um über Arrays oder array-ähnliche Objekte zu iterieren.
Das Ziel der for-in
-Anweisung ist es, über Objekteigenschaften zu iterieren. Diese Anweisung wird die Prototypenkette hochgehen, auch über geerbte Eigenschaften iterieren, was manchmal nicht erwünscht ist.
Außerdem ist die Reihenfolge der Iteration durch die Spezifikation nicht garantiert, was bedeutet, dass wenn Sie ein Array-Objekt "iterieren" möchten, mit dieser Anweisung können Sie nicht sicher sein, dass die Eigenschaften (Array-Indizes) in numerischer Reihenfolge besucht werden.
Zum Beispiel, in JScript (IE <= 8), ist die Reihenfolge der Aufzählung sogar bei Array-Objekten definiert, wie die Eigenschaften erstellt wurden:
var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';
for (var p in array) {
//... p wird bei IE "2", "1" und "0" sein
}
Auch, wenn es um geerbte Eigenschaften geht, wenn Sie beispielsweise das Array.prototype
Objekt erweitern (wie einige Bibliotheken wie MooTools es tun), werden diese Eigenschaften auch aufgezählt:
Array.prototype.last = function () { return this[this.length-1]; };
for (var p in []) { // ein leeres Array
// last wird aufgezählt werden
}
Wie ich schon sagte, um über Arrays oder array-ähnliche Objekte zu iterieren, ist es am besten, eine sequenzielle Schleife zu verwenden, wie zum Beispiel eine einfache for
/while
Schleife.
Wenn Sie nur die eigenen Eigenschaften eines Objekts aufzählen möchten (die nicht geerbt sind), können Sie die hasOwnProperty
-Methode verwenden:
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// prop ist nicht geerbt
}
}
Und einige empfehlen sogar, die Methode direkt von Object.prototype
aufzurufen, um Probleme zu vermeiden, falls jemand eine Eigenschaft namens hasOwnProperty
zu unserem Objekt hinzufügt:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// prop ist nicht geerbt
}
}
Siehe auch den Beitrag von David Humphrey Iterating over Objects in JavaScript Quickly - für Arrays ist for..in
viel langsamer als "normale" Schleifen.
Frage zum letzten Punkt über "hasOwnProperty": Wenn jemand "hasOwnProperty" auf einem Objekt überschreibt, bekommst du Probleme. Aber wirst du nicht die gleichen Probleme haben, wenn jemand "Object.prototype.hasOwnProperty" überschreibt? So oder so bringen sie dich durcheinander und es ist nicht deine Verantwortung, richtig?
Du sagst for..in
ist keine schlechte Praxis, aber es kann missbraucht werden. Hast du ein echtes Beispiel aus der Praxis, wo du wirklich alle Eigenschaften eines Objekts durchlaufen möchtest, einschließlich der geerbten Eigenschaften?
Es gibt drei Gründe, warum Sie for..in
nicht verwenden sollten, um über Array-Elemente zu iterieren:
for..in
wird über alle eigenen und geerbten Eigenschaften des Array-Objekts iterieren, die nicht DontEnum
sind; das bedeutet, dass wenn jemand Eigenschaften zum spezifischen Array-Objekt hinzufügt (es gibt gültige Gründe dafür - ich habe das auch gemacht) oder Array.prototype
geändert wird (was als schlechte Praxis in Code gilt, der gut mit anderen Skripten zusammenarbeiten soll), diese Eigenschaften ebenfalls durchlaufen werden; geerbte Eigenschaften können durch Überprüfung von hasOwnProperty()
ausgeschlossen werden, aber das hilft nicht bei Eigenschaften, die im Array-Objekt selbst festgelegt sind
for..in
garantiert nicht die Beibehaltung der Elementreihenfolge
Es ist langsam, weil Sie alle Eigenschaften des Array-Objekts und seiner gesamten Prototypenkette durchlaufen müssen und trotzdem nur den Namen der Eigenschaft erhalten, d. h. um den Wert zu erhalten, ist eine zusätzliche Suche erforderlich
Weil bei for...in das Objekt durchlaufen wird, das das Array enthält, nicht das Array selbst. Wenn ich eine Funktion in die Prototypenkette des Arrays hinzufüge, wird diese ebenfalls enthalten sein. Z.B.
Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for (var x in a) {
document.write(x + ' = ' + a[x]);
}
Dies wird geschrieben:
0 = foo
1 = bar
myOwnFunction = function() { alert(this); }
Und da man nie sicher sein kann, dass nichts zur Prototypenkette hinzugefügt wird, verwenden Sie einfach eine for-Schleife, um das Array aufzuzählen:
for (var i=0,x=a.length; i
Ab 2016 (ES6) können wir for ... of
zur Array-Iteration verwenden, wie bereits von John Slegers festgestellt.
Ich möchte einfach diesen einfachen Demonstrationscode hinzufügen, um die Dinge klarer zu machen:
Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";
console.log("for...of:");
var count = 0;
for (var item of arr) {
console.log(count + ":", item);
count++;
}
console.log("for...in:");
count = 0;
for (var item in arr) {
console.log(count + ":", item);
count++;
}
Die Konsole zeigt:
for...of:
0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz
for...in:
0: 5
1: foo
Mit anderen Worten:
for...of
zählt von 0 bis 5 und ignoriert auch Array.prototype.foo
. Es zeigt Array Werte.
for...in
listet nur die 5
auf, ignoriert die undefinierten Array-Indizes, fügt aber foo
hinzu. Es zeigt Array Eigenschaftsnamen.
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ürzlich gestellte Frage gesehen, bei der jemand das zu Ihnen gesagt hat, aber sie meinten nur für Arrays. Es gilt als schlechte Praxis, 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ärtsschleife. Gibt es eine andere Version der Vorwärtsschleife, die schneller ist?
1 Stimmen
@MattDiPasquale - ja, es ist umgekehrt, jedoch bei einer bekannten Grenze ermöglicht es eine optimale Verarbeitung, insbesondere in älteren Browsern durch Iteration über eine bekannte Menge vs. eine unbekannte Satzlänge durch Festlegung der Grenze zuerst. Es ist die Natur einer interpretierten Sprache.
0 Stimmen
@MarkSchultheiss Guter Kommentar. Man könnte auch die
for
-Schleife schreiben alsfor (var i = hColl.length; i--;) {}
, 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 den i-Zähler, da dies einen Unterschied macht und den Test vereinfacht. - Je älter der Browser ist, desto größer ist der Unterschied zwischenfor
undwhile
IMMER den "i" Zähler zwischenspeichern - und natürlich passt negativ nicht immer zur Situation, und das negativeverdeckt
den Code etwas für einige Leute. und beachten Sievar i = 1000; for (i; i; i--) {}
undvar b = 1000 for (b; b--;) {}
wobei i von 1000 bis 1 und b von 999 bis 0 geht. - Je älter der Browser ist, desto mehr tendiert der while dazu, die Leistung zu favorisieren.12 Stimmen
Du kannst auch schlau sein.
for(var i = 0, l = myArray.length; i < l; ++i) ...
ist die schnellste und beste Möglichkeit, um eine Vorwärtsiteration durchzuführen.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 handelt sich um Mikro-Optimierungen. Wenn Sie Zweifel haben, entscheiden Sie sich für lesbaren Code, nicht für eine hoch 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 Schleifensteuerstruktur.