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.

Relaterte artikler