Ich habe die letzte Frage gesehen, bei der jemand das zu Ihnen gesagt hat, aber sie waren nur für Arrays gedacht. Es wird als schlechte Praxis angesehen, Arrays zu durchlaufen, aber nicht unbedingt, Elemente eines Objekts zu durchlaufen.
mmurch
19
Viele Antworten mit "for" -Schleifen wie 'for (var i = 0; i <hColl.length; i ++) {}' vergleichen mit 'var i = hColl.length; während (i--) {} ', was, wenn es möglich ist, die letztere Form zu verwenden, wesentlich schneller ist. Ich weiß, dass dies tangential ist, dachte aber, ich würde dieses Bit hinzufügen.
Mark Schultheiss
2
@ MarkSchultheiss, aber das ist umgekehrte Iteration. Gibt es eine andere Version der Vorwärtsiteration, die schneller ist?
ma11hew28
5
@Wynand Verwenden Sie den var i = hCol1.length; for (i;i;i--;) {}Cache des i, da dies einen Unterschied macht, und vereinfachen Sie den Test. - Je älter der Browser ist, desto größer ist der Unterschied zwischen forund whileIMMER im Cache des "i" -Zählers - und natürlich passt das Negative nicht immer zur Situation und das Negative, während obfuscate der Code für manche Leute ein bisschen ist. und beachten Sie, var i = 1000; for (i; i; i--) {}und var b =1000 for (b; b--;) {}wo ich 1000 zu 1 und b 999 zu 0 gehe. - Je älter der Browser, desto mehr wird die Leistung tendenziell begünstigt.
Mark Schultheiss
9
Sie können auch klug sein. for(var i = 0, l = myArray.length; i < l; ++i) ...ist die schnellste und beste, die Sie mit Vorwärtsiteration erhalten können.
Mathieu Amiot
Antworten:
1557
Der Grund ist, dass ein Konstrukt:
var a =[];// Create a new empty array.
a[5]=5;// Perfectly legal JavaScript that resizes the array.for(var i =0; i < a.length; i++){// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);}/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
Bedenken Sie auch, dass JavaScript- Bibliotheken solche Aktionen ausführen können, die sich auf jedes von Ihnen erstellte Array auswirken:
// Somewhere deep in your JavaScript library...Array.prototype.foo =1;// Now you have no idea what the below code will do.var a =[1,2,3,4,5];for(var x in a){// Now foo is a part of EVERY array and // will show up here as a value of 'x'.
console.log(x);}/* Will display:
0
1
2
3
4
foo
*/
In der Vergangenheit haben einige Browser sogar "Länge", "toString" usw. durchlaufen!
Bobince
398
Denken Sie daran, zu verwenden, (var x in a)anstatt (x in a)- keine globale zu erstellen.
Chris Morgan
78
Die erste Ausgabe ist kein Grund, warum sie schlecht ist, sondern nur ein Unterschied in der Semantik. Das zweite Problem scheint mir ein Grund zu sein (zusätzlich zu den Konflikten zwischen Bibliotheken, die dasselbe tun), dass das Ändern des Prototyps eines integrierten Datentyps schlecht ist, anstatt dass das für ... in schlecht ist.
Stewart
86
@Stewart: Alle Objekte in JS sind assoziativ. Ein JS-Array ist ein Objekt, also ja, es ist auch assoziativ, aber dafür ist es nicht gedacht. Wenn Sie die Schlüssel eines Objekts durchlaufen möchten , verwenden Sie for (var key in object). Wenn Sie jedoch über die Elemente eines Arrays iterieren möchten , verwenden Sie for(var i = 0; i < array.length; i += 1).
Martijn
42
Sie sagten für das erste Beispiel, dass es über numerische Indizes von 0 bis 4 iteriert , wie jeder erwartet , ich erwarte , dass es von 0 bis 5 iteriert ! Wenn Sie an Position 5 ein Element hinzufügen, enthält das Array 6 Elemente (davon 5 undefiniert).
Stivlo
393
Die for-inAnweisung an sich ist keine "schlechte Praxis", kann jedoch missbraucht werden , um beispielsweise über Arrays oder Array-ähnliche Objekte zu iterieren .
Der Zweck der for-inErklärung ist aufzuzählen Objekteigenschaften über. Diese Aussage wird in der Prototypenkette auftauchen und auch geerbte Eigenschaften aufzählen , was manchmal nicht erwünscht ist.
Außerdem wird die Reihenfolge der Iteration nicht durch die Spezifikation garantiert. Wenn Sie also ein Array-Objekt "iterieren" möchten, können Sie mit dieser Anweisung nicht sicher sein, dass die Eigenschaften (Array-Indizes) in der numerischen Reihenfolge aufgerufen werden.
In JScript (IE <= 8) wird beispielsweise die Reihenfolge der Aufzählung auch für Array-Objekte definiert, wenn die Eigenschaften erstellt wurden:
var array =[];
array[2]='c';
array[1]='b';
array[0]='a';for(var p in array){//... p will be "2", "1" and "0" on IE}
Wenn Sie beispielsweise über geerbte Eigenschaften sprechen und das Array.prototypeObjekt erweitern (wie dies bei einigen Bibliotheken wie bei MooTools der Fall ist), werden diese Eigenschaften ebenfalls aufgelistet:
Array.prototype.last =function(){returnthis[this.length-1];};for(var p in []){// an empty array// last will be enumerated}
Wie ich bereits sagte, um Arrays oder Array-ähnliche Objekte zu durchlaufen , ist es am besten, eine sequentielle Schleife zu verwenden , z. B. eine Plain-Old for/ while-Schleife.
Wenn Sie nur die eigenen Eigenschaften eines Objekts auflisten möchten (diejenigen, die nicht vererbt wurden), können Sie die folgende hasOwnPropertyMethode verwenden:
for(var prop in obj){if(obj.hasOwnProperty(prop)){// prop is not inherited}}
Einige Leute empfehlen sogar, die Methode direkt von aufzurufen Object.prototype, um Probleme zu vermeiden, wenn jemand hasOwnPropertyunserem Objekt eine Eigenschaft mit dem Namen hinzufügt :
for(var prop in obj){if(Object.prototype.hasOwnProperty.call(obj, prop)){// prop is not inherited}}
Frage zum letzten Punkt zu "hasOwnProperty": Wenn jemand "hasOwnProperty" für ein Objekt überschreibt, treten Probleme auf. Aber haben Sie nicht die gleichen Probleme, wenn jemand "Object.prototype.hasOwnProperty" überschreibt? Wie auch immer, sie vermasseln dich und es liegt nicht in deiner Verantwortung, oder?
Scott Rippey
Sie sagen, es for..inist keine schlechte Praxis, aber es kann missbraucht werden. Haben Sie ein Beispiel für eine gute Praxis in der Praxis, bei dem Sie wirklich alle Objekteigenschaften einschließlich der geerbten Eigenschaften durchgehen wollten?
Mit dieser Antwort fand ich, dass mitfor (var p in array) { array[p]; }
equiman
117
Es gibt drei Gründe, warum Sie nicht for..inüber Array-Elemente iterieren sollten :
for..inwird alle eigenen und geerbten Eigenschaften des Array-Objekts durchlaufen, die es nicht sind DontEnum; Das bedeutet, wenn jemand dem spezifischen Array-Objekt Eigenschaften hinzufügt (es gibt gültige Gründe dafür - ich habe es selbst getan) oder geändert hat Array.prototype(was als schlechte Praxis in Code angesehen wird, der mit anderen Skripten gut funktionieren soll), werden diese Eigenschaften auch wiederholt werden; geerbte Eigenschaften können durch Überprüfen ausgeschlossen werden hasOwnProperty(), dies hilft Ihnen jedoch nicht bei den im Array-Objekt selbst festgelegten Eigenschaften
for..in Es wird nicht garantiert, dass die Elementreihenfolge erhalten bleibt
Es ist langsam, da Sie alle Eigenschaften des Array-Objekts und seiner gesamten Prototypenkette durchlaufen müssen und immer noch nur den Namen der Eigenschaft erhalten, dh um den Wert zu erhalten, ist eine zusätzliche Suche erforderlich
Denn for ... in zählt durch das Objekt auf, das das Array enthält, nicht das Array selbst. Wenn ich der Prototypkette des Arrays eine Funktion hinzufüge, wird diese ebenfalls berücksichtigt. Dh
Array.prototype.myOwnFunction =function(){ alert(this);}
a =newArray();
a[0]='foo';
a[1]='bar';for(x in a){
document.write(x +' = '+ a[x]);}
Dies wird schreiben:
0 = foo
1 = bar
myOwnFunction = function () {alert (this); }}
Und da Sie nie sicher sein können, dass der Prototypenkette nichts hinzugefügt wird, verwenden Sie einfach eine for-Schleife, um das Array aufzulisten:
Arrays sind Objekte, es gibt kein "Objekt, das das Array enthält".
RobG
41
Für sich genommen ist die Verwendung von For-In für Arrays nichts Falsches. For-in iteriert über die Eigenschaftsnamen eines Objekts, und im Fall eines "Out-of-the-Box" -Arrays entsprechen die Eigenschaften den Array-Indizes. (Der eingebaute in propertes wie length, toStringund so weiter sind nicht in der Iteration enthalten.)
Wenn Ihr Code (oder das von Ihnen verwendete Framework) Arrays oder dem Array-Prototyp benutzerdefinierte Eigenschaften hinzufügt, werden diese Eigenschaften in die Iteration einbezogen, was wahrscheinlich nicht Ihren Wünschen entspricht.
Einige JS-Frameworks wie Prototype ändern den Array-Prototyp. Andere Frameworks wie JQuery tun dies nicht. Mit JQuery können Sie For-In sicher verwenden.
Wenn Sie Zweifel haben, sollten Sie For-In wahrscheinlich nicht verwenden.
Eine alternative Methode zum Durchlaufen eines Arrays ist die Verwendung einer for-Schleife:
for(var ix=0;ix<arr.length;ix++) alert(ix);
Dies hat jedoch ein anderes Problem. Das Problem ist, dass ein JavaScript-Array "Löcher" haben kann. Wenn Sie definieren arrals:
var arr =["hello"];
arr[100]="goodbye";
Dann hat das Array zwei Elemente, aber eine Länge von 101. Die Verwendung von for-in ergibt zwei Indizes, während die for-Schleife 101 Indizes ergibt, wobei die 99 einen Wert von hat undefined.
Längere Antwort: Es lohnt sich einfach nicht, auch wenn keine sequentielle Elementreihenfolge und keine optimale Leistung erforderlich sind.
Lange Antwort: Es lohnt sich einfach nicht ...
Die Verwendung for (var property in array)wird dazu führen array, dass sie als Objekt durchlaufen wird, die Objektprototypkette durchläuft und letztendlich langsamer als eine indexbasierte forSchleife ist.
for (... in ...) Es ist nicht garantiert, dass die Objekteigenschaften wie erwartet in sequentieller Reihenfolge zurückgegeben werden.
Das Verwenden hasOwnProperty()und !isNaN()Überprüfen zum Filtern der Objekteigenschaften ist ein zusätzlicher Aufwand, der zu einer noch langsameren Leistung führt und den Hauptgrund für die erstmalige Verwendung negiert, dh aufgrund des präziseren Formats.
Aus diesen Gründen besteht nicht einmal ein akzeptabler Kompromiss zwischen Leistung und Komfort. Es gibt wirklich keinen Vorteil, es sei denn, die Absicht besteht darin, das Array als Objekt zu behandeln und Operationen an den Objekteigenschaften des Arrays auszuführen.
Zusätzlich zu den in anderen Antworten angegebenen Gründen möchten Sie möglicherweise nicht die Struktur "for ... in" verwenden, wenn Sie mit der Zählervariablen rechnen müssen, da die Schleife die Namen der Objekteigenschaften und damit der Variablen durchläuft ist eine Zeichenfolge.
Sie können +stattdessen das Präfix verwenden, es parseIntsei denn, Sie benötigen wirklich eine Ganzzahl oder ignorieren ungültige Zeichen.
Konrad Borowski
Die Verwendung parseInt()wird ebenfalls nicht empfohlen. Versuchen Sie es parseInt("025");und es wird fehlschlagen.
Derek 5 會 功夫
6
@Derek 朕 會 功夫 - Sie können definitiv verwenden parseInt. Das Problem ist, wenn Sie den Radix nicht einschließen, versuchen ältere Browser möglicherweise, die Zahl zu interpretieren (daher wird 025 oktal). Dies wurde in ECMAScript 5 behoben, aber es passiert immer noch für Zahlen, die mit "0x" beginnen (es interpretiert die Zahl als hexadezimal). Um auf der sicheren Seite zu sein, verwenden Sie den Radix, um die Nummer wie parseInt("025", 10)
Die Mechanik und Reihenfolge der Aufzählung der Eigenschaften ... ist nicht festgelegt ...
(Hervorhebung von mir.)
Das heißt, wenn ein Browser dies wollte, konnte er die Eigenschaften in der Reihenfolge durchlaufen, in der sie eingefügt wurden. Oder in numerischer Reihenfolge. Oder in lexikalischer Reihenfolge (wobei "30" vor "4" steht! Beachten Sie, dass alle Objektschlüssel - und damit alle Array-Indizes - tatsächlich Zeichenfolgen sind, was absolut sinnvoll ist). Es könnte sie per Bucket durchlaufen, wenn es Objekte als Hash-Tabellen implementiert. Oder nehmen Sie etwas davon und fügen Sie "rückwärts" hinzu. Ein Browser kann sogar nach dem Zufallsprinzip iterieren und ECMA-262-konform sein, sofern er jede Eigenschaft genau einmal besucht.
In der Praxis iterieren die meisten Browser derzeit gerne in ungefähr derselben Reihenfolge. Aber es gibt nichts zu sagen, dass sie müssen. Das ist implementierungsspezifisch und kann sich jederzeit ändern, wenn sich ein anderer Weg als weitaus effizienter herausstellt.
Wie auch immer, for... inbringt keine Konnotation der Ordnung mit sich. Wenn Sie sich für die Reihenfolge interessieren, geben Sie dies explizit an und verwenden Sie eine reguläre forSchleife mit einem Index.
Wie andere gesagt haben, erhalten Sie möglicherweise Schlüssel, die nicht in Ihrem Array enthalten sind oder die vom Prototyp geerbt wurden. Wenn also beispielsweise eine Bibliothek den Array- oder Objektprototypen eine Eigenschaft hinzufügt:
Array.prototype.someProperty =true
Sie erhalten es als Teil jedes Arrays:
for(var item in [1,2,3]){
console.log(item)// will log 1,2,3 but also "someProperty"}
Sie können dies mit der hasOwnProperty-Methode lösen:
var ary =[1,2,3];for(var item in ary){if(ary.hasOwnProperty(item)){
console.log(item)// will log only 1,2,3}}
Dies gilt jedoch für das Durchlaufen eines Objekts 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 durchlaufen, da das Array als Objekt behandelt wird, wie es in JS implementiert ist, und nicht als Array. Dies scheint eine kleine Sache zu sein, aber es kann Anwendungen wirklich vermasseln und ist schwer zu debuggen.
Object.keys(a).forEach( function(item) { console.log(item) } )Durchlaufen Sie ein Array eigener Eigenschaftsschlüssel, nicht die vom Prototyp geerbten.
Qwerty
2
Richtig, aber wie die For-In-Schleife muss sie nicht unbedingt in der richtigen Indexreihenfolge vorliegen. Außerdem funktioniert es nicht mit älteren Browsern, die ES5 nicht unterstützen.
Natürlich, aber dann manipulieren Sie den Prototyp, und das ist nicht immer eine gute Idee ... und trotzdem haben Sie das Problem der Bestellung ...
Lior
Und natürlich Grund Nummer drei: Sparse Arrays.
Ein besserer Oliver
16
Weil es durch Objektfelder und nicht durch Indizes auflistet. Sie können einen Wert mit dem Index "Länge" erhalten, und ich bezweifle, dass Sie dies möchten.
In Firefox 3 können Sie auch entweder arr.forEach oder for (var [i, v] in Iterator (arr)) {} verwenden, aber keines davon funktioniert im IE, obwohl Sie forEach-Methode selbst schreiben können.
Vava
und praktisch jede Bibliothek hat auch dafür ihre eigene Methode.
Vava
5
Diese Antwort ist falsch. "Länge" wird nicht in die For-In-Iteration einbezogen. Es sind nur Eigenschaften enthalten, die Sie selbst hinzufügen.
JacquesB
16
Ich glaube nicht, dass ich z. Die Antwort von Triptychon oder CMS, warum die Verwendung for...inin einigen Fällen vermieden werden sollte.
Ich möchte jedoch hinzufügen, dass es in modernen Browsern eine Alternative for...ingibt, die in den Fällen verwendet werden kann, in denen for...insie nicht verwendet werden können. Diese Alternative ist for...of:
for(var item of items){
console.log(item);}
Hinweis :
Leider unterstützt keine Version von Internet Explorer for...of( Edge 12+ ), sodass Sie etwas länger warten müssen, bis Sie sie in Ihrem clientseitigen Produktionscode verwenden können. Die Verwendung in Ihrem serverseitigen JS-Code sollte jedoch sicher sein (wenn Sie Node.js verwenden ).
Das Problem mit for ... in ...- und dies wird nur dann zu einem Problem, wenn ein Programmierer die Sprache nicht wirklich versteht. Es ist nicht wirklich ein Fehler oder so etwas - es ist, dass es über alle Mitglieder eines Objekts iteriert (nun, alle aufzählbaren Mitglieder, aber das ist ein Detail für den Moment). Wenn Sie nur die indizierten Eigenschaften eines Arrays durchlaufen möchten , besteht die einzige garantierte Möglichkeit, die Dinge semantisch konsistent zu halten, darin, einen ganzzahligen Index (dh eine for (var i = 0; i < array.length; ++i)Stilschleife) zu verwenden.
Jedem Objekt können beliebige Eigenschaften zugeordnet werden. Insbesondere das Laden zusätzlicher Eigenschaften auf eine Array-Instanz wäre nicht schrecklich. Code, der nur indizierte Array-ähnliche Eigenschaften sehen möchte, muss sich daher an einen ganzzahligen Index halten. Code, der genau weiß, was alle Eigenschaften for ... intut und wirklich braucht , dann ist das auch in Ordnung.
Schöne Erklärung Pointy. Nur neugierig. Wenn ich ein Array hätte, das sich innerhalb eines Objekts unter Multiplikationseigenschaften befindet, und for indiese Arrays im Vergleich zu einer regulären for-Schleife durchlaufen würden? (
Was
2
@ NiCkNewman gut das Objekt, nach dem Sie inin einer for ... inSchleife referenzieren , wird nur
Pointy
Aha. Nur neugierig, weil ich Objekte und Arrays in meinem Hauptspielobjekt habe und mich gefragt habe, ob das Inning schmerzhafter wäre als nur eine reguläre for-Schleife in den Indizes.
NiCk Newman
@NiCkNewman Nun, das Thema dieser ganzen Frage ist, dass Sie es einfach nicht for ... infür Arrays verwenden sollten. Es gibt viele gute Gründe, dies nicht zu tun. Es ist weniger ein Leistungsproblem als vielmehr ein Problem, bei dem sichergestellt wird, dass es nicht kaputt geht.
Pointy
Nun, meine Objekte sind technisch in einem Array gespeichert, deshalb habe ich mir Sorgen gemacht, so etwas wie: [{a:'hey',b:'hi'},{a:'hey',b:'hi'}]Aber ja, ich verstehe.
NiCk Newman
9
Aufgrund der Semantik ist die Art und for, inWeise, wie Arrays behandelt werden (dh wie jedes andere JavaScript-Objekt), nicht mit anderen gängigen Sprachen ausgerichtet.
// C#char[] a =newchar[]{'A','B','C'};
foreach (char x in a)System.Console.Write(x);//Output: "ABC"// Javachar[] a ={'A','B','C'};for(char x : a)System.out.print(x);//Output: "ABC"// PHP
$a = array('A','B','C');
foreach ($a as $x) echo $x;//Output: "ABC"// JavaScriptvar a =['A','B','C'];for(var x in a) document.write(x);//Output: "012"
TL & DR: Die Verwendung der for inSchleife in Arrays ist nicht böse, im Gegenteil.
Ich denke, die for inSchleife ist ein Juwel von JS, wenn sie in Arrays richtig verwendet wird . Es wird erwartet, dass Sie die volle Kontrolle über Ihre Software haben und wissen, was Sie tun. Lassen Sie uns die genannten Nachteile sehen und sie nacheinander widerlegen.
Es durchläuft auch geerbte Eigenschaften: Zuallererst sollten alle Erweiterungen Array.prototypevon mit using vorgenommen worden sein Object.defineProperty()und ihr enumerableDeskriptor sollte auf gesetzt sein false. Eine Bibliothek, die dies nicht tut, sollte überhaupt nicht verwendet werden.
Eigenschaften, die Sie später zur Vererbungskette hinzufügen, werden gezählt: Wenn Sie eine Array-Unterklassifizierung nach Object.setPrototypeOfoder nach Klasse durchführen extend. Verwenden Sie sollten wieder Object.defineProperty()die standardmäßig setzt den writable, enumerableund configurableEigenschaftendeskriptoren zu false. Sehen wir uns hier ein Beispiel für eine Unterklassifizierung von Arrays an ...
functionStack(...a){var stack =newArray(...a);Object.setPrototypeOf(stack,Stack.prototype);return stack;}Stack.prototype =Object.create(Array.prototype);// now stack has full access to array methods.Object.defineProperty(Stack.prototype,"constructor",{value:Stack});// now Stack is a proper constructorObject.defineProperty(Stack.prototype,"peak",{value:function(){// add Stack "only" methods to the Stack.prototype.returnthis[this.length-1];}});var s =newStack(1,2,3,4,1);
console.log(s.peak());
s[s.length]=7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);for(var i in s) console.log(s[i]);
Sie sehen also, die for inSchleife ist jetzt sicher, da Sie sich um Ihren Code gekümmert haben.
Die for inSchleife ist langsam: Hölle nein. Dies ist bei weitem die schnellste Methode zur Iteration, wenn Sie über spärliche Arrays laufen, die von Zeit zu Zeit benötigt werden. Dies ist einer der wichtigsten Performance-Tricks, die man kennen sollte. Sehen wir uns ein Beispiel an. Wir werden ein spärliches Array durchlaufen.
var a =[];
a[0]="zero";
a[10000000]="ten million";
console.time("for loop on array a:");for(var i=0; i < a.length; i++) a[i]&& console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");for(var i in a) a[i]&& console.log(a[i]);
console.timeEnd("for in loop on array a:");
@ Ravi Shanker Reddy Gutes Benchmarking eingerichtet. Wie ich in meiner Antwort erwähnt habe, for inüberstrahlt die Schleife die anderen "wenn" das Array spärlich ist und je größer es wird, desto größer wird es. Also habe ich den Bench-Test für ein spärliches Array mit arreiner Größe von ~ 10000 neu angeordnet, wobei nur 50 Elemente zufällig aus [42,"test",{t:1},null, void 0]zufälligen Indizes ausgewählt wurden. Sie werden den Unterschied sofort bemerken. - >> Hier nachschauen << - .
Reduzieren Sie den
8
Zusätzlich zu den anderen Problemen ist die Syntax "for..in" wahrscheinlich langsamer, da der Index eine Zeichenfolge und keine Ganzzahl ist.
var a =["a"]for(var i in a)
alert(typeof i)// 'string'for(var i =0; i < a.length; i++)
alert(typeof i)// 'number'
Wahrscheinlich spielt das keine große Rolle. Array-Elemente sind Eigenschaften eines Array-basierten oder Array-ähnlichen Objekts, und alle Objekteigenschaften verfügen über Zeichenfolgenschlüssel. Wenn Ihre JS-Engine es nicht irgendwie optimiert, wird es, selbst wenn Sie eine Zahl verwenden, in eine Zeichenfolge für die Suche umgewandelt.
CHao
Unabhängig von Leistungsproblemen: Wenn Sie mit JavaScript noch nicht vertraut sind, verwenden Sie var i in aden Index und erwarten Sie, dass er eine Ganzzahl ist. Wenn Sie so etwas tun, a[i+offset] = <value>werden Werte an völlig falschen Stellen platziert. ("1" + 1 == "11").
Szmoore
8
Ein wichtiger Aspekt ist, dass for...innur Eigenschaften durchlaufen werden, die in einem Objekt enthalten sind und deren Attribut enumerable property auf true gesetzt ist. Wenn man also versucht, ein Objekt mit zu iterieren, for...inwerden möglicherweise beliebige Eigenschaften übersehen, wenn das Attribut enumerable property false ist. Es ist durchaus möglich, das Attribut enumerable property für normale Array-Objekte so zu ändern, dass bestimmte Elemente nicht aufgelistet werden. Im Allgemeinen gelten die Eigenschaftsattribute jedoch eher für Funktionseigenschaften innerhalb eines Objekts.
Sie können den Wert des aufzählbaren Eigenschaftsattributs einer Eigenschaft überprüfen, indem Sie:
myobject.propertyIsEnumerable('myproperty')
Oder um alle vier Eigenschaftsattribute zu erhalten:
Dies ist eine in ECMAScript 5 verfügbare Funktion. In früheren Versionen war es nicht möglich, den Wert des Attributs enumerable property zu ändern (es wurde immer auf true gesetzt).
Das for/ inarbeitet mit zwei Arten von Variablen: Hashtabellen (assoziative Arrays) und Array (nicht assoziativ).
JavaScript bestimmt automatisch, wie es durch die Elemente geht. Wenn Sie also wissen, dass Ihr Array wirklich nicht assoziativ ist, können Sie es verwenden for (var i=0; i<=arrayLen; i++)und die Iteration für die automatische Erkennung überspringen.
Aber meiner Meinung nach ist es besser, for/ zu verwenden in. Der für diese automatische Erkennung erforderliche Prozess ist sehr klein.
Eine echte Antwort darauf hängt davon ab, wie der Browser den JavaScript-Code analysiert / interpretiert. Es kann zwischen Browsern wechseln.
Ich kann mir keine anderen Zwecke vorstellen, um for/ nicht zu verwenden in.
//Non-associativevar arr =['a','b','c'];for(var i in arr)
alert(arr[i]);//Associativevar arr ={
item1 :'a',
item2 :'b',
item3 :'c'};for(var i in arr)
alert(arr[i]);
Nicht genug - es ist vollkommen in Ordnung, Array-Instanzen beliebig benannte Eigenschaften hinzuzufügen, und diese werden anhand truevon hasOwnProperty()Überprüfungen getestet .
Pointy
Guter Punkt, danke. Ich war noch nie dumm genug, das selbst einem Array anzutun, also habe ich das nicht in Betracht gezogen!
JAL
1
@Pointy Ich habe dies nicht getestet, aber möglicherweise kann dies durch eine isNaNÜberprüfung jedes Eigenschaftsnamens behoben werden .
WynandB
1
@ Wynand interessante Idee; Ich verstehe jedoch nicht wirklich, warum es die Mühe wert ist, wenn das Iterieren mit einem einfachen numerischen Index so einfach ist.
Pointy
@WynandB Entschuldigung für die Beule, aber ich denke, eine Korrektur ist angebracht: Um isNaNzu überprüfen, ob eine Variable der spezielle Wert NaN ist oder nicht, kann sie nicht verwendet werden, um nach 'anderen Dingen als Zahlen' zu suchen (Sie können mit einem regulären Wert gehen Art dafür).
Doldt
6
Es ist nicht unbedingt schlecht (basierend auf dem, was Sie tun), aber im Fall von Arrays werden Array.prototypeSie seltsame Ergebnisse erzielen, wenn etwas hinzugefügt wurde. Wo Sie erwarten würden, dass diese Schleife dreimal ausgeführt wird:
var arr =['a','b','c'];for(var key in arr){...}
Wenn eine Funktion aufgerufen helpfulUtilityMethodhinzugefügt wurde Array‚s prototype, dann würde Ihre Schleife viermal läuft am Ende: keywäre 0, 1, 2, und helpfulUtilityMethod. Wenn Sie nur ganze Zahlen erwartet haben, hoppla.
Nur ein Hinweis zu SO - es gibt kein "oben", da Kommentare die Reihenfolge auf der Seite ständig ändern. Wir wissen also nicht genau, welchen Kommentar Sie meinen. Aus diesem Grund ist es gut, "im Kommentar einer Person" zu sagen.
JAL
@ JAL ... oder füge den Permalink zur Antwort hinzu.
WynandB
5
Die Verwendung der for...inSchleife für ein Array ist nicht falsch, obwohl ich mir vorstellen kann, warum Ihnen jemand das gesagt hat:
1.) Es gibt bereits eine Funktion oder Methode höherer Ordnung, die diesen Zweck für ein Array hat, aber mehr Funktionalität und schlankere Syntax hat, genannt 'forEach': Array.prototype.forEach(function(element, index, array) {} );
2.) Arrays haben immer eine Länge, aber for...inund forEachnicht eine Funktion für einen beliebigen Wert auszuführen, ist 'undefined'nur für die Indizes , die einen Wert definiert haben. Wenn Sie also nur einen Wert zuweisen, führen diese Schleifen eine Funktion nur einmal aus. Da ein Array jedoch aufgelistet ist, hat es immer eine Länge bis zum höchsten Index, der einen definierten Wert hat. Diese Länge kann jedoch bei Verwendung dieser Werte unbemerkt bleiben Schleifen.
3.) Der Standard für die Schleife führt eine Funktion so oft aus, wie Sie in den Parametern definiert haben. Da ein Array nummeriert ist, ist es sinnvoller zu definieren, wie oft Sie eine Funktion ausführen möchten. Im Gegensatz zu den anderen Schleifen kann die for-Schleife dann für jeden Index im Array eine Funktion ausführen, unabhängig davon, ob der Wert definiert ist oder nicht.
Im Wesentlichen können Sie jede Schleife verwenden, aber Sie sollten sich genau daran erinnern, wie sie funktionieren. Verstehen Sie die Bedingungen, unter denen sich die verschiedenen Schleifen wiederholen, ihre getrennten Funktionen und stellen Sie fest, dass sie für unterschiedliche Szenarien mehr oder weniger geeignet sind.
Es kann auch als eine bessere Vorgehensweise angesehen werden, die forEachMethode als die for...inSchleife im Allgemeinen zu verwenden, da sie einfacher zu schreiben ist und über mehr Funktionen verfügt. Daher möchten Sie möglicherweise die Gewohnheit haben, nur diese Methode und den Standard für, aber für Ihre zu verwenden Anruf.
Siehe unten, dass die ersten beiden Schleifen die Anweisungen console.log nur einmal ausführen, während der Standard für die Schleife die Funktion so oft ausführt, wie angegeben, in diesem Fall array.length = 6.
var arr =[];
arr[5]='F';for(var index in arr){
console.log(index);
console.log(arr[index]);
console.log(arr)}// 5// 'F'// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr){
console.log(index);
console.log(element);
console.log(arr);});// 5// 'F'// => Array (6) [undefined x 5, 6]for(var index =0; index < arr.length; index++){
console.log(index);
console.log(arr[index]);
console.log(arr);};// 0// undefined// => Array (6) [undefined x 5, 6]// 1// undefined// => Array (6) [undefined x 5, 6]// 2// undefined// => Array (6) [undefined x 5, 6]// 3// undefined// => Array (6) [undefined x 5, 6]// 4// undefined// => Array (6) [undefined x 5, 6]// 5// 'F'// => Array (6) [undefined x 5, 6]
Hier sind die Gründe, warum dies (normalerweise) eine schlechte Praxis ist:
for...inSchleifen durchlaufen alle ihre eigenen aufzählbaren Eigenschaften und die aufzählbaren Eigenschaften ihrer Prototypen. Normalerweise möchten wir in einer Array-Iteration nur über das Array selbst iterieren. Und obwohl Sie selbst möglicherweise nichts zum Array hinzufügen, können Ihre Bibliotheken oder Ihr Framework etwas hinzufügen.
Beispiel :
Array.prototype.hithere ='hithere';var array =[1,2,3];for(let el in array){// the hithere property will also be iterated over
console.log(el);}
for...inSchleifen garantieren keine bestimmte Iterationsreihenfolge . Obwohl die Reihenfolge heutzutage in den meisten modernen Browsern üblich ist, gibt es immer noch keine 100% ige Garantie.
for...inSchleifen ignorieren undefinedArray-Elemente, dh Array-Elemente, die noch nicht zugewiesen wurden.
Beispiel: :
const arr =[];
arr[3]='foo';// resize the array to 4
arr[4]=undefined;// add another element with value undefined to it// iterate over the array, a for loop does show the undefined elementsfor(let i =0; i < arr.length; i++){
console.log(arr[i]);}
console.log('\n');// for in does ignore the undefined elementsfor(let el in arr){
console.log(arr[el]);}
for ... in ist nützlich, wenn Sie an einem Objekt in JavaScript arbeiten, aber nicht für ein Array. Wir können jedoch nicht sagen, dass es ein falscher Weg ist, aber es wird nicht empfohlen. Sehen Sie sich dieses Beispiel unten an, indem Sie for ... in loop verwenden:
let txt ="";const person ={fname:"Alireza", lname:"Dezfoolian", age:35};for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
OK, machen wir es jetzt mit Array :
let txt ="";const person =["Alireza","Dezfoolian",35];for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
Wie Sie das Ergebnis gleich sehen ...
Aber lasst uns etwas ausprobieren, einen Prototyp für Array erstellen ...
Array.prototype.someoneelse ="someoneelse";
Jetzt erstellen wir ein neues Array ();
let txt ="";const arr =newArray();
arr[0]='Alireza';
arr[1]='Dezfoolian';
arr[2]=35;for(x in arr){
txt += arr[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35 someoneelse
Sie sehen die andere !!! ... In diesem Fall durchlaufen wir tatsächlich ein neues Array-Objekt!
Das ist einer der Gründe, warum wir es sorgfältig verwenden müssen, aber es ist nicht immer der Fall ...
Eine for ... in-Schleife zählt immer die Schlüssel auf. Objekteigenschaftsschlüssel sind immer Zeichenfolgen, auch die indizierten Eigenschaften eines Arrays:
var myArray =['a','b','c','d'];var total =0for(elem in myArray){
total += elem
}
console.log(total);// 00123
Da JavaScript-Elemente als Standardobjekteigenschaften gespeichert werden, ist es nicht ratsam, JavaScript-Arrays mit for ... in Schleifen zu durchlaufen, da normale Elemente und alle aufzählbaren Eigenschaften aufgelistet werden.
Obwohl diese Frage nicht speziell angesprochen wird, möchte ich hinzufügen, dass es einen sehr guten Grund gibt, niemals für ... in a zu verwenden NodeList(wie man es von einem querySelectorAllAufruf erhalten würde, da es stattdessen die zurückgegebenen Elemente überhaupt nicht sieht Iteration nur über die NodeList-Eigenschaften.
var i = hCol1.length; for (i;i;i--;) {}
Cache des i, da dies einen Unterschied macht, und vereinfachen Sie den Test. - Je älter der Browser ist, desto größer ist der Unterschied zwischenfor
undwhile
IMMER im Cache des "i" -Zählers - und natürlich passt das Negative nicht immer zur Situation und das Negative, währendobfuscate
der Code für manche Leute ein bisschen ist. und beachten Sie,var i = 1000; for (i; i; i--) {}
undvar b =1000 for (b; b--;) {}
wo ich 1000 zu 1 und b 999 zu 0 gehe. - Je älter der Browser, desto mehr wird die Leistung tendenziell begünstigt.for(var i = 0, l = myArray.length; i < l; ++i) ...
ist die schnellste und beste, die Sie mit Vorwärtsiteration erhalten können.Antworten:
Der Grund ist, dass ein Konstrukt:
kann manchmal ganz anders sein als die anderen:
Bedenken Sie auch, dass JavaScript- Bibliotheken solche Aktionen ausführen können, die sich auf jedes von Ihnen erstellte Array auswirken:
quelle
(var x in a)
anstatt(x in a)
- keine globale zu erstellen.for (var key in object)
. Wenn Sie jedoch über die Elemente eines Arrays iterieren möchten , verwenden Siefor(var i = 0; i < array.length; i += 1)
.Die
for-in
Anweisung an sich ist keine "schlechte Praxis", kann jedoch missbraucht werden , um beispielsweise über Arrays oder Array-ähnliche Objekte zu iterieren .Der Zweck der
for-in
Erklärung ist aufzuzählen Objekteigenschaften über. Diese Aussage wird in der Prototypenkette auftauchen und auch geerbte Eigenschaften aufzählen , was manchmal nicht erwünscht ist.Außerdem wird die Reihenfolge der Iteration nicht durch die Spezifikation garantiert. Wenn Sie also ein Array-Objekt "iterieren" möchten, können Sie mit dieser Anweisung nicht sicher sein, dass die Eigenschaften (Array-Indizes) in der numerischen Reihenfolge aufgerufen werden.
In JScript (IE <= 8) wird beispielsweise die Reihenfolge der Aufzählung auch für Array-Objekte definiert, wenn die Eigenschaften erstellt wurden:
Wenn Sie beispielsweise über geerbte Eigenschaften sprechen und das
Array.prototype
Objekt erweitern (wie dies bei einigen Bibliotheken wie bei MooTools der Fall ist), werden diese Eigenschaften ebenfalls aufgelistet:Wie ich bereits sagte, um Arrays oder Array-ähnliche Objekte zu durchlaufen , ist es am besten, eine sequentielle Schleife zu verwenden , z. B. eine Plain-Old
for
/while
-Schleife.Wenn Sie nur die eigenen Eigenschaften eines Objekts auflisten möchten (diejenigen, die nicht vererbt wurden), können Sie die folgende
hasOwnProperty
Methode verwenden:Einige Leute empfehlen sogar, die Methode direkt von aufzurufen
Object.prototype
, um Probleme zu vermeiden, wenn jemandhasOwnProperty
unserem Objekt eine Eigenschaft mit dem Namen hinzufügt :quelle
for..in
sind viel langsamer als "normale" Schleifen.for..in
ist keine schlechte Praxis, aber es kann missbraucht werden. Haben Sie ein Beispiel für eine gute Praxis in der Praxis, bei dem Sie wirklich alle Objekteigenschaften einschließlich der geerbten Eigenschaften durchgehen wollten?for (var p in array) { array[p]; }
Es gibt drei Gründe, warum Sie nicht
for..in
über Array-Elemente iterieren sollten :for..in
wird alle eigenen und geerbten Eigenschaften des Array-Objekts durchlaufen, die es nicht sindDontEnum
; Das bedeutet, wenn jemand dem spezifischen Array-Objekt Eigenschaften hinzufügt (es gibt gültige Gründe dafür - ich habe es selbst getan) oder geändert hatArray.prototype
(was als schlechte Praxis in Code angesehen wird, der mit anderen Skripten gut funktionieren soll), werden diese Eigenschaften auch wiederholt werden; geerbte Eigenschaften können durch Überprüfen ausgeschlossen werdenhasOwnProperty()
, dies hilft Ihnen jedoch nicht bei den im Array-Objekt selbst festgelegten Eigenschaftenfor..in
Es wird nicht garantiert, dass die Elementreihenfolge erhalten bleibtEs ist langsam, da Sie alle Eigenschaften des Array-Objekts und seiner gesamten Prototypenkette durchlaufen müssen und immer noch nur den Namen der Eigenschaft erhalten, dh um den Wert zu erhalten, ist eine zusätzliche Suche erforderlich
quelle
Denn for ... in zählt durch das Objekt auf, das das Array enthält, nicht das Array selbst. Wenn ich der Prototypkette des Arrays eine Funktion hinzufüge, wird diese ebenfalls berücksichtigt. Dh
Dies wird schreiben:
Und da Sie nie sicher sein können, dass der Prototypenkette nichts hinzugefügt wird, verwenden Sie einfach eine for-Schleife, um das Array aufzulisten:
Dies wird schreiben:
quelle
Für sich genommen ist die Verwendung von For-In für Arrays nichts Falsches. For-in iteriert über die Eigenschaftsnamen eines Objekts, und im Fall eines "Out-of-the-Box" -Arrays entsprechen die Eigenschaften den Array-Indizes. (Der eingebaute in propertes wie
length
,toString
und so weiter sind nicht in der Iteration enthalten.)Wenn Ihr Code (oder das von Ihnen verwendete Framework) Arrays oder dem Array-Prototyp benutzerdefinierte Eigenschaften hinzufügt, werden diese Eigenschaften in die Iteration einbezogen, was wahrscheinlich nicht Ihren Wünschen entspricht.
Einige JS-Frameworks wie Prototype ändern den Array-Prototyp. Andere Frameworks wie JQuery tun dies nicht. Mit JQuery können Sie For-In sicher verwenden.
Wenn Sie Zweifel haben, sollten Sie For-In wahrscheinlich nicht verwenden.
Eine alternative Methode zum Durchlaufen eines Arrays ist die Verwendung einer for-Schleife:
Dies hat jedoch ein anderes Problem. Das Problem ist, dass ein JavaScript-Array "Löcher" haben kann. Wenn Sie definieren
arr
als:Dann hat das Array zwei Elemente, aber eine Länge von 101. Die Verwendung von for-in ergibt zwei Indizes, während die for-Schleife 101 Indizes ergibt, wobei die 99 einen Wert von hat
undefined
.quelle
Ab 2016 (ES6) können wir
for…of
für die Array-Iteration verwenden, wie John Slegers bereits bemerkt hat.Ich möchte nur diesen einfachen Demonstrationscode hinzufügen, um die Dinge klarer zu machen:
Die Konsole zeigt:
Mit anderen Worten:
for...of
zählt von 0 bis 5 und ignoriert auchArray.prototype.foo
. Es zeigt Array- Werte .for...in
listet nur die5
undefinierten Array-Indizes auf, ignoriert sie jedochfoo
. Es zeigt Namen der Array- Eigenschaften .quelle
Kurze Antwort: Es lohnt sich einfach nicht.
Längere Antwort: Es lohnt sich einfach nicht, auch wenn keine sequentielle Elementreihenfolge und keine optimale Leistung erforderlich sind.
Lange Antwort: Es lohnt sich einfach nicht ...
for (var property in array)
wird dazu führenarray
, dass sie als Objekt durchlaufen wird, die Objektprototypkette durchläuft und letztendlich langsamer als eine indexbasiertefor
Schleife ist.for (... in ...)
Es ist nicht garantiert, dass die Objekteigenschaften wie erwartet in sequentieller Reihenfolge zurückgegeben werden.hasOwnProperty()
und!isNaN()
Überprüfen zum Filtern der Objekteigenschaften ist ein zusätzlicher Aufwand, der zu einer noch langsameren Leistung führt und den Hauptgrund für die erstmalige Verwendung negiert, dh aufgrund des präziseren Formats.Aus diesen Gründen besteht nicht einmal ein akzeptabler Kompromiss zwischen Leistung und Komfort. Es gibt wirklich keinen Vorteil, es sei denn, die Absicht besteht darin, das Array als Objekt zu behandeln und Operationen an den Objekteigenschaften des Arrays auszuführen.
quelle
Zusätzlich zu den in anderen Antworten angegebenen Gründen möchten Sie möglicherweise nicht die Struktur "for ... in" verwenden, wenn Sie mit der Zählervariablen rechnen müssen, da die Schleife die Namen der Objekteigenschaften und damit der Variablen durchläuft ist eine Zeichenfolge.
Zum Beispiel,
werde schreiben
wohingegen,
werde schreiben
Dies kann natürlich leicht durch Einbeziehen überwunden werden
in der Schleife, aber die erste Struktur ist direkter.
quelle
+
stattdessen das Präfix verwenden, esparseInt
sei denn, Sie benötigen wirklich eine Ganzzahl oder ignorieren ungültige Zeichen.parseInt()
wird ebenfalls nicht empfohlen. Versuchen Sie esparseInt("025");
und es wird fehlschlagen.parseInt
. Das Problem ist, wenn Sie den Radix nicht einschließen, versuchen ältere Browser möglicherweise, die Zahl zu interpretieren (daher wird 025 oktal). Dies wurde in ECMAScript 5 behoben, aber es passiert immer noch für Zahlen, die mit "0x" beginnen (es interpretiert die Zahl als hexadezimal). Um auf der sicheren Seite zu sein, verwenden Sie den Radix, um die Nummer wieparseInt("025", 10)
Abgesehen von der Tatsache, dass
for
...in
alle aufzählbaren Eigenschaften durchläuft (was nicht mit "allen Array-Elementen" identisch ist!), 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):(Hervorhebung von mir.)
Das heißt, wenn ein Browser dies wollte, konnte er die Eigenschaften in der Reihenfolge durchlaufen, in der sie eingefügt wurden. Oder in numerischer Reihenfolge. Oder in lexikalischer Reihenfolge (wobei "30" vor "4" steht! Beachten Sie, dass alle Objektschlüssel - und damit alle Array-Indizes - tatsächlich Zeichenfolgen sind, was absolut sinnvoll ist). Es könnte sie per Bucket durchlaufen, wenn es Objekte als Hash-Tabellen implementiert. Oder nehmen Sie etwas davon und fügen Sie "rückwärts" hinzu. Ein Browser kann sogar nach dem Zufallsprinzip iterieren und ECMA-262-konform sein, sofern er jede Eigenschaft genau einmal besucht.
In der Praxis iterieren die meisten Browser derzeit gerne in ungefähr derselben Reihenfolge. Aber es gibt nichts zu sagen, dass sie müssen. Das ist implementierungsspezifisch und kann sich jederzeit ändern, wenn sich ein anderer Weg als weitaus effizienter herausstellt.
Wie auch immer,
for
...in
bringt keine Konnotation der Ordnung mit sich. Wenn Sie sich für die Reihenfolge interessieren, geben Sie dies explizit an und verwenden Sie eine regulärefor
Schleife mit einem Index.quelle
Hauptsächlich zwei Gründe:
Eins
Wie andere gesagt haben, erhalten Sie möglicherweise Schlüssel, die nicht in Ihrem Array enthalten sind oder die vom Prototyp geerbt wurden. Wenn also beispielsweise eine Bibliothek den Array- oder Objektprototypen eine Eigenschaft hinzufügt:
Sie erhalten es als Teil jedes Arrays:
Sie können dies mit der hasOwnProperty-Methode lösen:
Dies gilt jedoch für das Durchlaufen eines Objekts 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 durchlaufen, da das Array als Objekt behandelt wird, wie es in JS implementiert ist, und nicht als Array. Dies scheint eine kleine Sache zu sein, aber es kann Anwendungen wirklich vermasseln und ist schwer zu debuggen.
quelle
Object.keys(a).forEach( function(item) { console.log(item) } )
Durchlaufen Sie ein Array eigener Eigenschaftsschlüssel, nicht die vom Prototyp geerbten.array.forEach
indem Sie bestimmten Code in Ihre Skripte einfügen. Siehe Polyfill developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Weil es durch Objektfelder und nicht durch Indizes auflistet. Sie können einen Wert mit dem Index "Länge" erhalten, und ich bezweifle, dass Sie dies möchten.
quelle
Ich glaube nicht, dass ich z. Die Antwort von Triptychon oder CMS, warum die Verwendung
for...in
in einigen Fällen vermieden werden sollte.Ich möchte jedoch hinzufügen, dass es in modernen Browsern eine Alternative
for...in
gibt, die in den Fällen verwendet werden kann, in denenfor...in
sie nicht verwendet werden können. Diese Alternative istfor...of
:Hinweis :
Leider unterstützt keine Version von Internet Explorer
for...of
( Edge 12+ ), sodass Sie etwas länger warten müssen, bis Sie sie in Ihrem clientseitigen Produktionscode verwenden können. Die Verwendung in Ihrem serverseitigen JS-Code sollte jedoch sicher sein (wenn Sie Node.js verwenden ).quelle
for-of
, nicht wahrfor-in
?Das Problem mit
for ... in ...
- und dies wird nur dann zu einem Problem, wenn ein Programmierer die Sprache nicht wirklich versteht. Es ist nicht wirklich ein Fehler oder so etwas - es ist, dass es über alle Mitglieder eines Objekts iteriert (nun, alle aufzählbaren Mitglieder, aber das ist ein Detail für den Moment). Wenn Sie nur die indizierten Eigenschaften eines Arrays durchlaufen möchten , besteht die einzige garantierte Möglichkeit, die Dinge semantisch konsistent zu halten, darin, einen ganzzahligen Index (dh einefor (var i = 0; i < array.length; ++i)
Stilschleife) zu verwenden.Jedem Objekt können beliebige Eigenschaften zugeordnet werden. Insbesondere das Laden zusätzlicher Eigenschaften auf eine Array-Instanz wäre nicht schrecklich. Code, der nur indizierte Array-ähnliche Eigenschaften sehen möchte, muss sich daher an einen ganzzahligen Index halten. Code, der genau weiß, was alle Eigenschaften
for ... in
tut und wirklich braucht , dann ist das auch in Ordnung.quelle
for in
diese Arrays im Vergleich zu einer regulären for-Schleife durchlaufen würden? (in
in einerfor ... in
Schleife referenzieren , wird nurfor ... in
für Arrays verwenden sollten. Es gibt viele gute Gründe, dies nicht zu tun. Es ist weniger ein Leistungsproblem als vielmehr ein Problem, bei dem sichergestellt wird, dass es nicht kaputt geht.[{a:'hey',b:'hi'},{a:'hey',b:'hi'}]
Aber ja, ich verstehe.Aufgrund der Semantik ist die Art und
for, in
Weise, wie Arrays behandelt werden (dh wie jedes andere JavaScript-Objekt), nicht mit anderen gängigen Sprachen ausgerichtet.quelle
TL & DR: Die Verwendung der
for in
Schleife in Arrays ist nicht böse, im Gegenteil.Ich denke, die
for in
Schleife ist ein Juwel von JS, wenn sie in Arrays richtig verwendet wird . Es wird erwartet, dass Sie die volle Kontrolle über Ihre Software haben und wissen, was Sie tun. Lassen Sie uns die genannten Nachteile sehen und sie nacheinander widerlegen.Array.prototype
von mit using vorgenommen worden seinObject.defineProperty()
und ihrenumerable
Deskriptor sollte auf gesetzt seinfalse
. Eine Bibliothek, die dies nicht tut, sollte überhaupt nicht verwendet werden.Object.setPrototypeOf
oder nach Klasse durchführenextend
. Verwenden Sie sollten wiederObject.defineProperty()
die standardmäßig setzt denwritable
,enumerable
undconfigurable
Eigenschaftendeskriptoren zufalse
. Sehen wir uns hier ein Beispiel für eine Unterklassifizierung von Arrays an ...Sie sehen also, die
for in
Schleife ist jetzt sicher, da Sie sich um Ihren Code gekümmert haben.for in
Schleife ist langsam: Hölle nein. Dies ist bei weitem die schnellste Methode zur Iteration, wenn Sie über spärliche Arrays laufen, die von Zeit zu Zeit benötigt werden. Dies ist einer der wichtigsten Performance-Tricks, die man kennen sollte. Sehen wir uns ein Beispiel an. Wir werden ein spärliches Array durchlaufen.quelle
for in
überstrahlt die Schleife die anderen "wenn" das Array spärlich ist und je größer es wird, desto größer wird es. Also habe ich den Bench-Test für ein spärliches Array mitarr
einer Größe von ~ 10000 neu angeordnet, wobei nur 50 Elemente zufällig aus[42,"test",{t:1},null, void 0]
zufälligen Indizes ausgewählt wurden. Sie werden den Unterschied sofort bemerken. - >> Hier nachschauen << - .Zusätzlich zu den anderen Problemen ist die Syntax "for..in" wahrscheinlich langsamer, da der Index eine Zeichenfolge und keine Ganzzahl ist.
quelle
var i in a
den Index und erwarten Sie, dass er eine Ganzzahl ist. Wenn Sie so etwas tun,a[i+offset] = <value>
werden Werte an völlig falschen Stellen platziert. ("1" + 1 == "11").Ein wichtiger Aspekt ist, dass
for...in
nur Eigenschaften durchlaufen werden, die in einem Objekt enthalten sind und deren Attribut enumerable property auf true gesetzt ist. Wenn man also versucht, ein Objekt mit zu iterieren,for...in
werden möglicherweise beliebige Eigenschaften übersehen, wenn das Attribut enumerable property false ist. Es ist durchaus möglich, das Attribut enumerable property für normale Array-Objekte so zu ändern, dass bestimmte Elemente nicht aufgelistet werden. Im Allgemeinen gelten die Eigenschaftsattribute jedoch eher für Funktionseigenschaften innerhalb eines Objekts.Sie können den Wert des aufzählbaren Eigenschaftsattributs einer Eigenschaft überprüfen, indem Sie:
Oder um alle vier Eigenschaftsattribute zu erhalten:
Dies ist eine in ECMAScript 5 verfügbare Funktion. In früheren Versionen war es nicht möglich, den Wert des Attributs enumerable property zu ändern (es wurde immer auf true gesetzt).
quelle
Das
for
/in
arbeitet mit zwei Arten von Variablen: Hashtabellen (assoziative Arrays) und Array (nicht assoziativ).JavaScript bestimmt automatisch, wie es durch die Elemente geht. Wenn Sie also wissen, dass Ihr Array wirklich nicht assoziativ ist, können Sie es verwenden
for (var i=0; i<=arrayLen; i++)
und die Iteration für die automatische Erkennung überspringen.Aber meiner Meinung nach ist es besser,
for
/ zu verwendenin
. Der für diese automatische Erkennung erforderliche Prozess ist sehr klein.Eine echte Antwort darauf hängt davon ab, wie der Browser den JavaScript-Code analysiert / interpretiert. Es kann zwischen Browsern wechseln.
Ich kann mir keine anderen Zwecke vorstellen, um
for
/ nicht zu verwendenin
.quelle
Array
esObject
auch istfor ... in
arbeitet mit Objekten. Es gibt keine automatische Erkennung.Weil es über Eigenschaften iteriert, die zu Objekten in der Prototypenkette gehören, wenn Sie nicht vorsichtig sind.
Sie können verwenden
for.. in
, stellen Sie jedoch sicher, dass Sie jede Eigenschaft mit hasOwnProperty überprüfen .quelle
true
vonhasOwnProperty()
Überprüfungen getestet .isNaN
Überprüfung jedes Eigenschaftsnamens behoben werden .isNaN
zu überprüfen, ob eine Variable der spezielle Wert NaN ist oder nicht, kann sie nicht verwendet werden, um nach 'anderen Dingen als Zahlen' zu suchen (Sie können mit einem regulären Wert gehen Art dafür).Es ist nicht unbedingt schlecht (basierend auf dem, was Sie tun), aber im Fall von Arrays werden
Array.prototype
Sie seltsame Ergebnisse erzielen, wenn etwas hinzugefügt wurde. Wo Sie erwarten würden, dass diese Schleife dreimal ausgeführt wird:Wenn eine Funktion aufgerufen
helpfulUtilityMethod
hinzugefügt wurdeArray
‚sprototype
, dann würde Ihre Schleife viermal läuft am Ende:key
wäre0
,1
,2
, undhelpfulUtilityMethod
. Wenn Sie nur ganze Zahlen erwartet haben, hoppla.quelle
Sie sollten die
for(var x in y)
nur für Eigenschaftslisten verwenden, nicht für Objekte (wie oben erläutert).quelle
Die Verwendung der
for...in
Schleife für ein Array ist nicht falsch, obwohl ich mir vorstellen kann, warum Ihnen jemand das gesagt hat:1.) Es gibt bereits eine Funktion oder Methode höherer Ordnung, die diesen Zweck für ein Array hat, aber mehr Funktionalität und schlankere Syntax hat, genannt 'forEach':
Array.prototype.forEach(function(element, index, array) {} );
2.) Arrays haben immer eine Länge, aber
for...in
undforEach
nicht eine Funktion für einen beliebigen Wert auszuführen, ist'undefined'
nur für die Indizes , die einen Wert definiert haben. Wenn Sie also nur einen Wert zuweisen, führen diese Schleifen eine Funktion nur einmal aus. Da ein Array jedoch aufgelistet ist, hat es immer eine Länge bis zum höchsten Index, der einen definierten Wert hat. Diese Länge kann jedoch bei Verwendung dieser Werte unbemerkt bleiben Schleifen.3.) Der Standard für die Schleife führt eine Funktion so oft aus, wie Sie in den Parametern definiert haben. Da ein Array nummeriert ist, ist es sinnvoller zu definieren, wie oft Sie eine Funktion ausführen möchten. Im Gegensatz zu den anderen Schleifen kann die for-Schleife dann für jeden Index im Array eine Funktion ausführen, unabhängig davon, ob der Wert definiert ist oder nicht.
Im Wesentlichen können Sie jede Schleife verwenden, aber Sie sollten sich genau daran erinnern, wie sie funktionieren. Verstehen Sie die Bedingungen, unter denen sich die verschiedenen Schleifen wiederholen, ihre getrennten Funktionen und stellen Sie fest, dass sie für unterschiedliche Szenarien mehr oder weniger geeignet sind.
Es kann auch als eine bessere Vorgehensweise angesehen werden, die
forEach
Methode als diefor...in
Schleife im Allgemeinen zu verwenden, da sie einfacher zu schreiben ist und über mehr Funktionen verfügt. Daher möchten Sie möglicherweise die Gewohnheit haben, nur diese Methode und den Standard für, aber für Ihre zu verwenden Anruf.Siehe unten, dass die ersten beiden Schleifen die Anweisungen console.log nur einmal ausführen, während der Standard für die Schleife die Funktion so oft ausführt, wie angegeben, in diesem Fall array.length = 6.
quelle
Hier sind die Gründe, warum dies (normalerweise) eine schlechte Praxis ist:
for...in
Schleifen durchlaufen alle ihre eigenen aufzählbaren Eigenschaften und die aufzählbaren Eigenschaften ihrer Prototypen. Normalerweise möchten wir in einer Array-Iteration nur über das Array selbst iterieren. Und obwohl Sie selbst möglicherweise nichts zum Array hinzufügen, können Ihre Bibliotheken oder Ihr Framework etwas hinzufügen.Beispiel :
for...in
Schleifen garantieren keine bestimmte Iterationsreihenfolge . Obwohl die Reihenfolge heutzutage in den meisten modernen Browsern üblich ist, gibt es immer noch keine 100% ige Garantie.for...in
Schleifen ignorierenundefined
Array-Elemente, dh Array-Elemente, die noch nicht zugewiesen wurden.Beispiel: :
quelle
for ... in ist nützlich, wenn Sie an einem Objekt in JavaScript arbeiten, aber nicht für ein Array. Wir können jedoch nicht sagen, dass es ein falscher Weg ist, aber es wird nicht empfohlen. Sehen Sie sich dieses Beispiel unten an, indem Sie for ... in loop verwenden:
OK, machen wir es jetzt mit Array :
Wie Sie das Ergebnis gleich sehen ...
Aber lasst uns etwas ausprobieren, einen Prototyp für Array erstellen ...
Jetzt erstellen wir ein neues Array ();
Sie sehen die andere !!! ... In diesem Fall durchlaufen wir tatsächlich ein neues Array-Objekt!
Das ist einer der Gründe, warum wir es sorgfältig verwenden müssen, aber es ist nicht immer der Fall ...
quelle
Eine for ... in-Schleife zählt immer die Schlüssel auf. Objekteigenschaftsschlüssel sind immer Zeichenfolgen, auch die indizierten Eigenschaften eines Arrays:
quelle
Von https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
quelle
Obwohl diese Frage nicht speziell angesprochen wird, möchte ich hinzufügen, dass es einen sehr guten Grund gibt, niemals für ... in a zu verwenden
NodeList
(wie man es von einemquerySelectorAll
Aufruf erhalten würde, da es stattdessen die zurückgegebenen Elemente überhaupt nicht sieht Iteration nur über die NodeList-Eigenschaften.Im Falle eines einzelnen Ergebnisses erhielt ich:
was erklärte, warum meine
for (node in nodes) node.href = newLink;
versagte.quelle