JavaScript for...in vs for
Tror du det er stor forskjell på for...in og for-løkker? Hvilken type «for» foretrekker du å bruke, og hvorfor?
La oss si at vi har et array av assosiative arrays:
var myArray = [{'key': 'value'}, {'key': 'value1'}];
Så vi kan iterere:
for (var i = 0; i < myArray.length; i++)
Og :
for (var i in myArray)
Jeg ser ikke en stor forskjell. Er det noen ytelsesproblemer?
Svar #1
Valget bør baseres på hvilken idiom som er best forstått.
Et array blir iterert ved hjelp av:
for (var i = 0; i < a.length; i++)
//do stuff with a[i]
Et objekt som brukes som et assosiativt array, itereres ved hjelp av:
for (var key in o)
//do stuff with o[key]
Med mindre du har jordrystende grunner, hold deg til det etablerte bruks mønsteret.
Svar #2
Douglas Crockford anbefaler i JavaScript: The Good Parts (side 24) å unngå å bruke for in-setningen.
Hvis du bruker for in for å gå gjennom egenskapsnavn i et objekt, er ikke resultatene ordnet. Verre: Du kan få uventede resultater; det inkluderer medlemmer arvet fra prototypekjeden og navnene på metoder.
Alt bortsett fra egenskapene kan filtreres ut med .hasOwnProperty. Dette kodeeksempelet gjør det du sannsynligvis ønsket opprinnelig:
for (var name in obj) {
if (Object.prototype.hasOwnProperty.call(obj, name)) {
// DO STUFF
}
}
Svar #3
Til orientering - jQuery-brukere
jQuerys each(callback)-metode bruker som standard for( ; ; )-løkke, og vil bruke for( in ) bare hvis lengden er undefined.
Derfor vil jeg si at det er trygt å anta riktig rekkefølge når man bruker denne funksjonen.
Eksempel:
$(['a','b','c']).each(function() {
alert(this);
});
//Outputs "a" then "b" then "c"
Ulempen med å bruke dette er at hvis du gjør noe logikk som ikke er UI-relatert, vil funksjonene dine være mindre bærbare til andre rammeverk. each()-funksjonen er sannsynligvis best å reservere for bruk med jQuery-selektorer, og for( ; ; ) kan være å anbefale ellers.
Svar #4
Det er ytelsesforskjeller avhengig av hvilken type løkke du bruker og hvilken nettleser du bruker.
For eksempel:
for (var i = myArray.length-1; i >= 0; i--)
er nesten dobbelt så rask på noen nettlesere enn:
for (var i = 0; i < myArray.length; i++)
Men med mindre arrayene dine er KJEMPESTORE eller du går gjennom dem konstant, er alle raske nok. Jeg tviler seriøst på at loop gjennom arrayer er en flaskehals i prosjektet ditt (eller i noe annet prosjekt for den saks skyld)
Svar #5
Merk at den opprinnelige Array.forEach-metoden nå er bredt støttet.
Svar #6
Oppdatert svar for 2012 nåværende versjon av alle store nettlesere - Chrome, Firefox, IE9, Safari og Opera støtter ES5s native array.forEach.
Med mindre du har en grunn til å støtte IE8 på egenhånd (med tanke på at ES5-shim eller Chrome Frame kan gis til disse brukerne, noe som vil gi et korrekt JS-miljø), er det renere å bare bruke språkets riktige syntaks:
myArray.forEach(function(item, index) {
console.log(item, index);
});
Full dokumentasjon for array.forEach() finnes på MDN.
Svar #7
De to er ikke det samme når matrisen er sparsom.
var array = [0, 1, 2, , , 5];
for (var k in array) {
// Not guaranteed by the language spec to iterate in order.
alert(k); // Outputs 0, 1, 2, 5.
// Behavior when loop body adds to the array is unclear.
}
for (var i = 0; i < array.length; ++i) {
// Iterates in order.
// i is a number, not a string.
alert(i); // Outputs 0, 1, 2, 3, 4, 5
// Behavior when loop body modifies array is clearer.
}
Svar #8
Bruke forEach for å hoppe over prototype-kjeden
Bare en rask tilleggskommentar til @nailer sitt svar ovenfor, bruk av forEach med Object.keys betyr at du kan unngå å iterere over prototype-kjeden uten å måtte bruke hasOwnProperty.
var Base = function () {
this.coming = "hey";
};
var Sub = function () {
this.leaving = "bye";
};
Sub.prototype = new Base();
var tst = new Sub();
for (var i in tst) {
console.log(tst.hasOwnProperty(i) + i + tst[i]);
}
Object.keys(tst).forEach(function (val) {
console.log(val + tst[val]);
});
Svar #9
Jeg er enig i at du bør velge iterasjonsmetoden etter ditt behov. Jeg vil faktisk foreslå at du aldri går gjennom native Array med for in-strukturen. Det er mye tregere og, som Chase Seibert påpekte nettopp nå, ikke kompatibelt med Prototype-rammeverket.
Det finnes en utmerket referanse på forskjellige måter å bruke løkker på som du absolutt bør se på hvis du jobber med JavaScript. Ikke gjør tidlige optimaliseringer, men du bør ha den informasjonen et sted i bakhodet.
Jeg ville bruke for in for å få alle egenskapene til et objekt, noe som er spesielt nyttig når du feilsøker skriptene dine. For eksempel liker jeg å ha denne linjen tilgjengelig når jeg utforsker ukjente objekter:
l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);
Det dumper innholdet av hele objektet (sammen med metodekroppene) til min Firebug-logg. Veldig praktisk.
