JavaScript Foreach:En omfattende guide til begyndere

Lige til pointen! Hvad er forEach helt præcist i JavaScript, hvor kommer det fra, og hvad er anvendelsesmulighederne – herunder hvordan man bruger det på de "array-lignende" objekter?

I slutningen af ​​denne vejledning finder du svar på disse spørgsmål.

Hvis du er bekendt med array, lad os tage et kig på dette:

const lists = ['item1', 'item2', 'item3']

Og hvis du console.log(lists) eller blot tilføje linjen til din konsol, får du dine data. Det er ret ligetil.

Notationen ovenfor kaldes array literal og det er meget nemt at bruge.

Men internt bruger JavaScript-motoren i stedet den indbyggede Array() konstruktørfunktion som sådan:

const lists = new Array('item1', 'item2', 'item3')

Dette er den tilsvarende objektnotation.

Hvis du erstatter den bogstavelige notation med ovenstående, vil du se den samme struktur i konsollen.

Hvis du nu går et skridt videre og tjekker denne Array-konstruktør, vil du finde en prototype egenskab bestående af flere metoder. Lad os tage et kig rigtig hurtigt.

Indtast Array.prototype. i konsollen finder du forEach sammen med andre metoder:

Det er der, det kommer fra.

Okay. Hvis du ved, hvordan prototypeegenskaben fungerer i OOP, alle de metoder, der er defineret på den, inklusive forEach er nedarvet og tilgængelige for objektforekomsten. I dette tilfælde er lists array.

Det betyder, at vi kan kalde det direkte på lists array sådan:

lists.forEach()

Så hvad er ForEach helt præcist?

ForEach er et af midlerne til at sløjfe eller iterere gennem arrays. I moderne JavaScript bruges det almindeligvis i stedet for det traditionelle for loop.

Lad os tage et kig på dens syntaks:

forEach(callback(currentElement, index, arr), thisValue)

Den modtager en callback fungerer som et argument og udfører det for hver element i arrayet. Denne tilbagekaldsfunktion accepterer tre argumenter – det aktuelle element (som er påkrævet), dets index og det array, som elementet tilhører – dvs. arr .

Også thisValue parameter (hvis angivet) vil blive brugt som værdien af ​​this i tilbagekaldet.

Det er det, lad os se det i praksis!

Vi starter med en simpel for-løkke så du har et glimt af, hvordan løkkerne fungerer. Dette vil også tjene som en genopfriskning for os.

Så konfigurer din grundlæggende .html og link en .js fil (eller brug blot browserens udviklerværktøjer, hvis du er fortrolig med det).

I din .js fil, skal du tilføje følgende kode:

const lists = ['item1', , 'item2', 'item3']
const newList = []

for (let i = 0; i < lists.length; i++) {
  newList.push(lists[i]);
}

console.log(newList);

Her går vi gennem lists array og derefter skubbe hvert itererede element ind i en newList array.

Hvis du gemmer filen og tjekker newList i konsollen, bør du se dette output:

["item1", undefined, "item2", "item3"]

Vi får en undefined værdi på det første indeks, lists[1] dvs. det andet array-element.

Lad os se, hvordan forEach metode håndterer den samme iteration.

Erstat for-løkken med denne:

const lists = ['item1', , 'item2', 'item3']
const newList = []

lists.forEach(function (list) {
  newList.push(list);
})

console.log(newList);

Udgangen:

["item1", "item2", "item3"]

Hvad sker der?

Ved at bruge forEach metode, siger vi, at "for hvert af de itererede elementer (dvs. individuelle list ) i lists array, lad os udføre en bestemt funktion.

Igen skubber funktionen hvert itererede element ind i en newList array. Men når du kommer til det andet array-element, forEach springer den tomme plads over og gå videre.

Lad os optimere vores kode yderligere.

Vi kan gøre det mere kortfattet ved at bruge ES6 pilefunktionen. Hvis du omskriver tilbagekaldet ved hjælp af pilefunktionen, skal du have:

const lists = ['item1', , 'item2', 'item3']
const newList = []

lists.forEach((list) => newList.push(list))
console.log(newList);

Gem og besøg konsollen igen. Det burde fungere perfekt.

Godt. Det er en god start.

Lad os tage et skridt videre ved at anvende de andre valgfri tilbagekaldsparametre.

Du skal blot tilføje følgende kode i .js fil:

let numbers = [2, 4, 6, 8, 10];

numbers.forEach((number, index, arr) => {
  arr[index] = number * 2; // arr = [2, 4, 6, 8, 10]
})

console.log(numbers);

Som sædvanlig er forEach går gennem numbers array og udfører tilbagekaldsfunktionen for hvert element. I dette tilbagekald er det eneste, vi gør, at opdatere numbers array ved at gange dets nuværende itererede element med 2.

Og vi refererer til arrayet og dets indekser ved hjælp af arr[index] .

Gem filen.

Udgangen:

[4, 8, 12, 16, 20]

Går videre.

Anvendelse af det andet argument i forEach-metoden – dvs. thisValue

Nogle gange arbejder du muligvis med this søgeord i din forEach sløjfe. Og hvis du er bekendt med søgeordet, ved du, at det kan referere til et andet objekt.

For at binde dette søgeord til dit objekt af interesse, JavaScript forEach giver os thisValue argument som angivet i dets syntaks.

Lad os se en use case.

Start med at tilføje følgende kode i din .js fil:

function MyNumber() {
  this.data = [];
}

MyNumber.prototype.multiply = function () {
  console.log("test");
}

const num = new MyNumber()

num.multiply();

Hvis du nogensinde har skrevet objektorienteret kodestil, bør du være bekendt med ovenstående.

Vi definerede en konstruktørfunktion, MyNumber indeholdende en data ejendom og en multiply metode.

I øjeblikket gør koden ikke meget. Hvis du gemmer det og tjekker konsollen, vil du kun se en "test"-meddelelse.

Lad os nu opdatere koden, så du har:

function MyNumber() {
  this.data = [];
}

MyNumber.prototype.multiply = function (numbers) {
  numbers.forEach(function (number) {
    console.log(this);
    this.data.push(number * 2)
  })
}

const num = new MyNumber()

num.multiply([2, 4, 6]);
console.log(num.data);

Fokusområdet er multiply metode. Dens funktion er at modtage array som et argument, som vi går igennem ved hjælp af forEach metode.

Logikken her er, at vi ønsker at opdatere den tomme data array ved at skubbe nye array-elementer ind i det. Så vi skal henvise til data egenskab ved hjælp af this søgeord i tilbagekaldet.

Men hvis du gemmer filen og ser på konsollen, vil du se noget som dette:

Ud over konsolfejlen ser vi også Window objekt, fordi vi console.log(this) inde i forEach .

Det betyder, at this refererer til det globale objekt, som er Window . I stedet vil vi have this for at referere til den aktuelle objektinstans.

Det er her det andet argument i forEach kommer ind. Så tilføj blot this som argumentet og gem din fil. Du burde være god.

numbers.forEach(function (number) {
  console.log(this);
  this.data.push(number * 2)
}, this)

Hvis du tjekker konsollen igen, vil du se den this peger nu på objektforekomsten.

Produktion:

[4, 8, 12]

Brug af pilefunktionen som tilbagekald

Du kan undgå at bruge this som den anden parameter i forEach metode, hvis du erstatter dens tilbagekaldsfunktion med en pilefunktion. Ligesom:

numbers.forEach((number) => {
  console.log(this);
  this.data.push(number * 2)
})

Gem og test din kode. Det vil fungere, fordi pilfunktionen leksikalsk binder this værdi – dvs. værdien af ​​this søgeord bestemmes af dets kontekst eller omgivende omfang.

ForEach() returnerer altid udefineret

Du skal være forsigtig med dette, fordi det er nemt at glemme. Hvis du forsøger at returnere en forEach funktion, får du en undefined værdi.

Lad os se. Tilføj følgende kode i .js fil.

let numbers = [2, 4, 6, 8, 10];

const myNum = numbers.forEach(number => {
  return number * 2
})

console.log(myNum);

Som du kan se, returnerer vi forEach logik og tildeling af resultatet i myNum variabel.

Hvis du gemmer filen og åbner konsollen, vil du se en undefined værdi.

Nå, hvis du gerne vil returnere noget, så brug en anden metode som map(). Den har en definition svarende til forEach .

Lad os tage den samme kode og erstatte forEach med map metode som sådan:

let numbers = [2, 4, 6, 8, 10];

const myNum = numbers.map(number => {
  return number * 2
})

console.log(myNum);

Gem din fil, og besøg konsollen igen.

Produktion:

[4, 8, 12, 16, 20]

I modsætning til forEach() , map() metoden returnerer et nyt array, der indeholder resultaterne af at kalde en funktion på hvert array-element.

Arbejde med array-lignende objekter

Hvis du nogensinde har arbejdet med HTML DOM, bør du være bekendt med DOM metoder såsom getElementsByClassName() , getElementsByTagName() og querySelectorAll() .

Disse metoder kan bruges til at samle en masse elementer i et dokument. Og de returnerer enten en HTMLCollection eller en NodeList (begge er array-lignende objekter).

I dette afsnit lærer du, hvordan du itererer disse objekter ved hjælp af forEach .

Lad os se et praktisk eksempel. Tilføj følgende til din .html fil:

<ul class="list">
  <li class="list-item">item1</li>
  <li class="list-item">item2</li>
  <li class="list-item">item3</li>
  <li class="list-item">item4</li>
</ul>

Hvis du prøver at få fat i alle li elementer ved hjælp af DOM-metoderne, har du:

let itemsByClassName = document.getElementsByClassName('list-item')
console.log(itemsByClassName);

Produktion:

HTMLCollection(4) [li.list-item, li.list-item, li.list-item, li.list-item]
0: li.list-item
1: li.list-item
2: li.list-item
3: li.list-item
length: 4
__proto__ : HTMLCollection

ELLER…

let itemsByQuerySelector = document.querySelectorAll('.list-item')
console.log(itemsByQuerySelector);

Produktion:

NodeList(4) [li.list-item, li.list-item, li.list-item, li.list-item]
0: li.list-item
1: li.list-item
2: li.list-item
3: li.list-item
length: 4
__proto__ : NodeList

Ud fra outputtet skulle du tro, at de er arrays, fordi de ser sådan ud (da de indeholder indekser og længdeegenskaber). Men det er de ikke!

Både HTMLCollection og NodeList er objekter, der ligner et array, derfor Array-lignende genstande.

Hvad det betyder er, at de fleste af Array-metoderne er tilgængelige via Array.prototype. ville ikke være tilgængelig på dem. I stedet arver de metoder fra Object.prototype .

Så hvordan kan vi bruge forEach at gå gennem li elementer?

Heldigvis NodeList arver et par af disse Array-metoder, hvoraf forEach er en af ​​dem. Så vi kan gentage NodeList direkte ved hjælp af forEach metode som sådan:

let itemsByQuerySelector = document.querySelectorAll('.list-item')

itemsByQuerySelector.forEach(item => console.log(item.innerText))

I tilbagekaldet logger vi den indre tekst for hvert af de itererede elementer.

Produktion:

item1
item2
item3
item4

Hvis du gør det samme med HTMLCollection , får du denne fejl:

Uncaught TypeError: itemsByClassName.forEach is not a function

For at gå gennem denne type Array-lignende objekt kan vi bruge en call() metode. Dette giver os mulighed for at bruge en metode, der hører til et andet objekt.

I vores tilfælde ønsker vi at ringe til forEach metode tilgængelig på Array.prototype objekt og derefter bruge det på HTMLCollection .

Din kode skal se sådan ud:

let itemsByClassName = document.getElementsByClassName('list-item')

Array.prototype.forEach.call(itemsByClassName, (item) => console.log(item.innerText))

Gem og tjek konsollen. Du bør have det samme output.

Konvertering af array-lignende objekter til array

Et alternativ til at gå gennem de array-lignende objekter er først at transformere det til et array. Vi kan bruge en metode kaldet Array.from() eller brug Spread-syntaksen ( ) for det.

Lad os hurtigt tage et kig.

let itemsByClassName = document.getElementsByClassName('list-item')
let itemsArray = Array.from(itemsByClassName)
console.log(itemsArray);

Det er ret ligetil.

Produktion:

(4) [li.list-item, li.list-item, li.list-item, li.list-item]
0: li.list-item
1: li.list-item
2: li.list-item
3: li.list-item
length: 4
__proto__ : Array(0)

Resultatet er det samme, hvis du bruger spredningsoperatoren sådan:

let itemsByClassName = document.getElementsByClassName('list-item')
let itemsArray = [...itemsByClassName]
console.log(itemsArray);

Den spredningssyntaks ( ) "spreder" eller udvider det array-lignende objekt inden for de firkantede parenteser, [] gør det til et korrekt array.

Nu kan du bruge forEach metode direkte på arrayet.

Endnu et eksempel på et array-lignende objekt.

Før vi samler op, kan du støde på denne struktur af Array-lignende objekter:

const arrayLike = {
  0: 'item1',
  1: 'item2',
  2: 'item3',
  length: 3
};

I modsætning til den tidligere engang er denne type ikke itererbar, og du kan ikke bruge spread-syntaksen til at konvertere den til en matrix. I dette tilfælde skal du blot bruge Array.from() ligesom:

const newArray = Array.from(arrayLike)
console.log(newArray);

Produktion:

["item1", "item2", "item3"]

Derfra kan du ringe til forEach metode på output til at gå igennem.

Eller hvis du vil, skal du blot bruge den tidligere metode til at kalde forEach indirekte ved at bruge call() metode som sådan:

const arrayLike = {
  0: 'item1',
  1: 'item2',
  2: 'item3',
  length: 3
};

Array.prototype.forEach.call(arrayLike, (item) => console.log(item))

Hvis du gemmer filen og tjekker konsollen, bør du se dine elementer.

Konklusion

Vi har set næsten alle use cases af forEach-metoden. Fra iteration gennem et simpelt array til at arbejde med de array-lignende objekter og næsten alt, hvad der er derimellem. Nu skulle du være i stand til at anvende det i dit projekt.

Hvis du har spørgsmål, så lad mig det vide gennem kommentarsektionen.

Og hvis du kan lide dette selvstudie, så prøv at dele det rundt på nettet og følg mig på Twitter for flere opdateringer.