For-each over een array in JavaScript?
Hoe kan ik met JavaScript door alle items in een array lopen?
Ik dacht dat het zoiets was als dit:
forEach(instance in theArray)
Waarbij deArray
mijn array is, maar dit lijkt niet te kloppen.
4427
3
TL;DR
for-in
unless you use it with safeguards or are at least aware of why it might bite you.for-of
lus (alleen ES2015+),Array#forEach
([spec
][1] | [MDN
][2]) (of zijn verwantensome
en dergelijke) (alleen ES5+),for
lus,of
for-in
met beveiligingen. Maar er is veel meer te ontdekken, lees verder...JavaScript heeft krachtige semantiek voor looping door arrays en array-achtige objecten. Ik'heb het antwoord in twee delen gesplitst: Opties voor echte arrays, en opties voor dingen die gewoon array-achtig zijn, zoals het
arguments
object, andere iterable objecten (ES2015+), DOM collecties, enzovoort. Ik'zal snel opmerken dat je de ES2015 opties nu kunt gebruiken, zelfs op ES5 engines, door transpiling van ES2015 naar ES5. Zoek naar "ES2015 transpiling" / "ES6 transpiling" voor meer... Oké, laten we eens kijken naar onze opties:Voor de eigenlijke Arrays
Je hebt drie opties in [ECMAScript 5][3] ("ES5"), de versie die op dit moment het breedst ondersteund wordt, en nog twee die toegevoegd zijn in [ECMAScript 2015][4] ("ES2015", "ES6"):
forEach
en aanverwanten (ES5+)for
lusfor-in
correctfor-of
(gebruik impliciet een iterator) (ES2015+)1. Gebruik
forEach
en aanverwanteIn elke vaag-moderne omgeving (dus niet IE8) waar je toegang hebt tot de
Array
functies die door ES5 zijn toegevoegd (direct of met behulp van polyfills), kun jeforEach
([spec
][1] | [MDN
][2]) gebruiken:forEach
accepteert een callback functie en, optioneel, een waarde om te gebruiken alsthis
bij het aanroepen van die callback (hierboven niet gebruikt). De callback wordt aangeroepen voor elke entry in de array, in volgorde, waarbij niet-bestaande entries in sparse arrays worden overgeslagen. Hoewel ik hierboven maar één argument gebruikte, wordt de callback aangeroepen met drie: De waarde van elke entry, de index van die entry, en een verwijzing naar de array waar je're iteratie over gaat (voor het geval je functie die niet al bij de hand heeft). Tenzij je'verouderde browsers zoals IE8 ondersteunt (die NetApps laat zien op iets meer dan 4% marktaandeel vanaf dit schrijven in september 2016), kun je gelukkigforEach
gebruiken in een algemene webpagina zonder een shim. Als je toch verouderde browsers moet ondersteunen, is shimmen/polyfillen vanforEach
eenvoudig te doen (zoek naar "es5 shim" voor verschillende opties).forEach
heeft het voordeel dat je geen index en waarde variabelen in de containing scope hoeft te declareren, omdat ze als argumenten aan de iteratie functie worden meegegeven, en dus mooi scoped naar alleen die iteratie. Als je je zorgen maakt over de runtime kosten van het maken van een functie-aanroep voor elke array entry, wees dat dan niet; details. Bovendien,forEach
is de "loop through them all" functie, maar ES5 definieerde verschillende andere nuttige "work your way through the array and do things" functies, waaronder:every
][5] (stopt de lus de eerste keer dat de callbackfalse
of iets vals teruggeeft)some
][6] (stopt met de eerste keer dat de callbacktrue
of iets waarachtigs teruggeeft)filter
][7] (creëert een nieuwe array met elementen waar de filter functietrue
retourneert en met weglating van de elementen waar hetfalse
retourneert)map
][8] (creëert een nieuwe array van de waarden geretourneerd door de callback)reduce
][9] (bouwt een waarde op door herhaaldelijk de callback aan te roepen, waarbij eerdere waarden worden doorgegeven; zie de spec voor de details; handig voor het optellen van de inhoud van een array en vele andere dingen)reduceRight
][10] (zoalsreduce
, maar werkt in aflopende in plaats van oplopende volgorde)2. Gebruik een eenvoudige
for
lusSoms zijn de oude manieren de beste:
Als de lengte van de array niet zal veranderen tijdens de lus, en het is in performance-gevoelige code (onwaarschijnlijk), een iets gecompliceerdere versie die de lengte op voorhand grijpt zou een tiny beetje sneller kunnen zijn:
En/of terug tellen:
Maar met moderne JavaScript engines is het zeldzaam dat je dat laatste beetje sap moet uitpersen. In ES2015 en hoger, kun je je index en waarde variabelen lokaal maken voor de
for
loop:En als je dat doet, wordt niet alleen
value
maar ookindex
opnieuw aangemaakt voor elke lus iteratie, wat betekent dat closures die in de lus body worden gemaakt een verwijzing houden naar deindex
(envalue
) die voor die specifieke iteratie is aangemaakt:Als je vijf divs had, zou je "Index is: 0" als je op de eerste klikte en "Index is: 4" als je op de laatste hebt geklikt. Dit werkt niet als u
var
gebruikt in plaats vanlet
.3. Gebruik
for-in
correct.Je krijgt van mensen te horen dat je
for-in
moet gebruiken, maar [dat is niet waarfor-in
voor is][11].for-in
loopt door de numerable properties van een object, niet de indexen van een array. De volgorde is niet gegarandeerd, zelfs niet in ES2015 (ES6). ES2015+ definieert wel een volgorde voor objecteigenschappen (via[[OwnPropertyKeys]]
,[[Enumerate]]
, en dingen die ze gebruiken zoals [Object.getOwnPropertyKeys
][12]), maar het definieert niet datfor-in
die volgorde zal volgen. (Details in [dit andere antwoord][13].) De enige echte use-cases voorfor-in
op een array zijn: het is een [sparse arrays][14] met grote gaten erin, of U gebruikt niet-elementeigenschappen en die wilt u in de lus opnemen Als we alleen naar dat eerste voorbeeld kijken: Je kuntfor-in
gebruiken om die sparese array elementen te bezoeken als je de juiste voorzorgsmaatregelen gebruikt:Noot: Dit antwoord is hopeloos verouderd. Voor een modernere aanpak, kijk naar de methoden die beschikbaar zijn op een array. Methoden van belang kunnen zijn:
De standaard manier om een array te itereren in JavaScript is een vanilla
for
-lus:Merk echter op dat deze aanpak alleen goed is als je een dichte array hebt, en elke index wordt bezet door een element. Als de array sparse is, dan kun je performance problemen krijgen met deze aanpak, omdat je over veel indices zult itereren die echt niet bestaan in de array. In dit geval is een
for .. in
-lus misschien een beter idee. Hoewel, je moet de juiste voorzorgsmaatregelen nemen om er zeker van te zijn dat alleen de gewenste eigenschappen van de array (dat wil zeggen, de array elementen) worden gebruikt, omdat defor..in
-lus ook opgesomd zal worden in oudere browsers, of als de extra eigenschappen gedefinieerd zijn alsenumerable
.In ECMAScript 5 komt er een forEach methode op het array prototype, maar deze wordt niet ondersteund in legacy browsers. Dus om het consistent te kunnen gebruiken moet je of een omgeving hebben die het ondersteunt (bijvoorbeeld Node.js voor server side JavaScript), of een "Polyfill" gebruiken. De Polyfill voor deze functionaliteit is echter triviaal en omdat het de code makkelijker leesbaar maakt, is het een goede polyfill om op te nemen.
Als je een lus wilt maken over een array, gebruik dan de standaard driedelige
for
lus.Je kunt de prestaties optimaliseren door
myArray.length
te cachen of er achterwaarts overheen te lopen.