For-each över en array i JavaScript?
Hur kan jag gå igenom alla poster i en array med JavaScript?
Jag trodde att det var något liknande:
forEach(instance in theArray)
Där theArray
är min array, men det verkar inte stämma.
4427
3
TL;DR
for-in
om du inte använder det med skyddsåtgärder eller om du åtminstone är medveten om varför det kan bita dig.for-of
-slinga (endast ES2015+),Array#forEach
([spec
][1] | [MDN
][2]) (eller dess släktingarsome
och liknande) (endast ES5+),for
-slinga,eller
for-in
med skyddsåtgärder. Men det finns mycket mer att utforska, läs vidare...JavaScript har en kraftfull semantik för slinga genom arrayer och array-liknande objekt. Jag har delat upp svaret i två delar: Alternativ för äkta matriser och alternativ för saker som bara är array-liknande, som
arguments
-objektet, andra iterable-objekt (ES2015+), DOM-samlingar och så vidare. Jag ska snabbt notera att du kan använda ES2015-alternativen nu, även på ES5-motorer, genom att transportera ES2015 till ES5. Sök efter "ES2015 transpiling" / "ES6 transpiling" för mer... Okej, låt oss titta på våra alternativ:För faktiska matriser
Du har tre alternativ i [ECMAScript 5][3] ("ES5"), den version som har mest stöd för tillfället, och ytterligare två som lades till i [ECMAScript 2015][4] ("ES2015", "ES6"):
forEach
och relaterade (ES5+)for
-slinga.for-in
korrekt.for-of
(använd implicit en iterator) (ES2015+)1. Använd
forEach
och relateradeI alla vagt moderna miljöer (alltså inte IE8) där du har tillgång till
Array
-funktionerna som lades till i ES5 (direkt eller med hjälp av polyfills) kan du användaforEach
([spec
][1] | [MDN
][2]):forEach
accepterar en callback-funktion och, som alternativ, ett värde som ska användas somthis
när callback-funktionen anropas (används inte ovan). Callback-funktionen anropas för varje post i matrisen, i turordning, och hoppar över icke-existerande poster i glesa matriser. Även om jag bara använde ett argument ovan, anropas callbacken med tre argument: Värdet för varje post, indexet för den posten och en referens till matrisen som du itererar över (om din funktion inte redan har den i handen). Om du inte stöder föråldrade webbläsare som IE8 (som NetApps visar har en marknadsandel på drygt 4 % när detta skrivs i september 2016) kan du utan problem användaforEach
i en allmän webbsida utan shim. Om du behöver stödja föråldrade webbläsare är det lätt att shimma/polyfyllaforEach
(sök efter "es5 shim" för flera alternativ).forEach
har den fördelen att du inte behöver deklarera indexerings- och värdevariabler i det innehållande scope, eftersom de levereras som argument till iterationsfunktionen och därmed är väl avgränsade till just den iterationen. Om du är orolig för körtidskostnaden för att göra ett funktionsanrop för varje arraypost behöver du inte vara det; details. Dessutom ärforEach
funktionen "loop through them all" men ES5 definierade flera andra användbara "work your way through the array and do things" funktioner, inklusive:every
][5] (slutar att slinga första gången som callbacken returnerarfalse
eller något annat felaktigt).some
][6] (stoppar looping första gången callbacken returnerartrue
eller något sanningsenligt)filter
][7] (skapar en ny array med element där filterfunktionen returnerartrue
och utelämnar de element där den returnerarfalse
).map
][8] (skapar en ny array av de värden som återges av callback-funktionen).reduce
][9] (bygger upp ett värde genom att upprepade gånger anropa callbacken och skicka in tidigare värden; se specifikationen för detaljer; användbart för att summera innehållet i en array och många andra saker)reduceRight
][10] (somreduce
, men arbetar i fallande snarare än stigande ordning)2. Använd en enkel
for
-slingaIbland är de gamla sätten bäst:
Om längden på arrayen inte ändras under slingan och det är i prestandakänslig kod (osannolikt) kan en något mer komplicerad version som tar fram längden i förväg vara en tiny bit snabbare:
Och/eller att räkna baklänges:
Men med moderna JavaScript-motorer är det sällan du behöver ta ut den sista biten juice. I ES2015 och senare kan du göra dina index- och värdevariabler lokala för
for
-slingan:Och när du gör det skapas inte bara
value
utan ävenindex
för varje loop-iteration, vilket innebär att closures som skapas i loop-kroppen behåller en referens tillindex
(ochvalue
) som skapats för den specifika iterationen:Om du hade fem divs skulle du få "Index är: 0" om du klickar på den första och "Index är: 4" om du klickar på den sista. Detta fungerar inte om du använder
var
istället förlet
.3. Använd
for-in
korrekt.Du'får folk som säger att du ska använda
for-in
, men [det'är inte vadfor-in
är till för][11].for-in
loopar genom de uppräkneliga egenskaperna hos ett objekt, inte indexen i en array. Ordningsföljden är inte garanterad, inte ens i ES2015 (ES6). ES2015+ definierar en ordning för objektets egenskaper (via[[OwnPropertyKeys]]
,[[Enumerate]]
, och saker som använder dem som [Object.getOwnPropertyKeys
][12]), men det definierar inte attfor-in
ska följa den ordningen. (Detaljer i [detta andra svar][13].) De enda verkliga användningsområdena förfor-in
på en array är:for-in
för att besöka dessa sparese array-element om du använder lämpliga skyddsåtgärder:Note: Detta svar är hopplöst föråldrat. För ett mer modernt tillvägagångssätt, se de metoder som finns tillgängliga för en array. Metoder av intresse kan vara:
Standardmetoden för att iterera en array i JavaScript är en vanlig
for
-slinga:Observera dock att detta tillvägagångssätt endast är bra om du har en tät array och varje index är upptaget av ett element. Om arrayen är gles kan du få prestandaproblem med detta tillvägagångssätt, eftersom du kommer att iterera över en massa index som inte verkligen finns i arrayen. I det här fallet kan en
for .. in
-slinga vara en bättre idé. **Du måste dock använda lämpliga skyddsåtgärder för att se till att endast de önskade egenskaperna hos matrisen (dvs. matrisens element) behandlas, eftersomfor..in
-slingan också kommer att räknas upp i äldre webbläsare, eller om de ytterligare egenskaperna är definierade somenumerable
.I ECMAScript 5 kommer det att finnas en forEach-metod på arrayprototypen, men den stöds inte i äldre webbläsare. Så för att kunna använda den konsekvent måste du antingen ha en miljö som stöder den (till exempel Node.js för JavaScript på serversidan) eller använda en "Polyfill". Polyfill för denna funktionalitet är dock trivial och eftersom den gör koden lättare att läsa är det en bra polyfill att inkludera.
Om du vill gå i en loop över en array använder du den vanliga tredelade
for
-slingan.Du kan optimera prestandan genom att cachelagra
myArray.length
eller genom att iterera över den baklänges.