Přímo k věci! Co přesně je forEach v JavaScriptu, odkud pochází a jaké jsou případy použití – včetně toho, jak jej použít na „pole podobné“ objekty?
Na konci této příručky najdete odpovědi na tyto otázky.
Pokud jste obeznámeni s polem, pojďme se podívat na toto:
const lists = ['item1', 'item2', 'item3']
A pokud console.log(lists)
nebo jednoduše přidejte řádek do své konzole, získáte svá data. To je docela přímočaré.
Výše uvedený zápis se nazývá array literal a jeho použití je velmi jednoduché.
Ale interně, JavaScript engine místo toho používá vestavěný Array()
funkce konstruktoru takto:
const lists = new Array('item1', 'item2', 'item3')
Toto je ekvivalentní zápis objektu.
Pokud nahradíte doslovný zápis výše uvedeným, uvidíte stejnou strukturu v konzole.
Nyní, když půjdete o krok dále a zkontrolujete tento konstruktor Array, najdete prototype
vlastnost sestávající z několika metod. Pojďme se na to rychle podívat.
Zadejte Array.prototype.
v konzole najdete forEach
vedle jiných metod:
Odtud to pochází.
OK. Pokud víte, jak vlastnost prototype funguje v OOP, všechny metody v ní definované včetně forEach
jsou zděděné a dostupné pro instanci objektu. V tomto případě lists
pole.
To znamená, že to můžeme volat přímo na lists
pole takto:
lists.forEach()
Co tedy přesně je ForEach?
ForEach je jedním z prostředků smyčkování nebo iterace přes pole. V moderním JavaScriptu se běžně používá místo tradiční smyčky for.
Podívejme se na jeho syntaxi:
forEach(callback(currentElement, index, arr), thisValue)
Obdrží callback
funguje jako argument a provede jej pro každý prvek v poli. Tato funkce zpětného volání přijímá tři argumenty – aktuální prvek (který je povinný), jeho index
a pole, ke kterému prvek patří – tj. arr
.
Také thisValue
parametr (pokud je zadán) bude použit jako hodnota this
ve zpětném volání.
To je ono, podívejme se na to v praxi!
Začneme jednoduchou smyčkou for takže máte pohled na to, jak smyčky fungují. To nám také poslouží jako osvěžení.
Nastavte si tedy základní .html
a propojit .js
(nebo jednoduše použijte vývojářské nástroje prohlížeče, pokud vám to vyhovuje).
Ve vašem .js
soubor, přidejte následující kód:
const lists = ['item1', , 'item2', 'item3']
const newList = []
for (let i = 0; i < lists.length; i++) {
newList.push(lists[i]);
}
console.log(newList);
Zde procházíme smyčkou lists
pole a poté vložení každého iterovaného prvku do newList
pole.
Pokud soubor uložíte a zaškrtnete newList
v konzole byste měli vidět tento výstup:
["item1", undefined, "item2", "item3"]
Dostáváme undefined
hodnota na prvním indexu, lists[1]
tj. druhá položka pole.
Podívejme se, jak forEach
metoda zpracovává stejnou iteraci.
Nahraďte cyklus for tímto:
const lists = ['item1', , 'item2', 'item3']
const newList = []
lists.forEach(function (list) {
newList.push(list);
})
console.log(newList);
výstup:
["item1", "item2", "item3"]
Co se děje?
Pomocí forEach
říkáme, že „pro každý iterovaný prvek (tj. jednotlivé list
) v lists
pole, provedeme určitou funkci.
Funkce opět vkládá každý iterovaný prvek do newList
pole. Ale když se dostaneme k druhé položce pole, forEach
přeskočí prázdný slot a pokračuje.
Pojďme náš kód dále optimalizovat.
Můžeme to zkrátit pomocí funkce šipky ES6. Pokud přepíšete zpětné volání pomocí funkce šipky, měli byste mít:
const lists = ['item1', , 'item2', 'item3']
const newList = []
lists.forEach((list) => newList.push(list))
console.log(newList);
Uložte a znovu navštivte konzolu. Mělo by to fungovat perfektně.
Dobrý. To je skvělý začátek.
Udělejme krok dále použitím dalších volitelných parametrů zpětného volání.
Jednoduše přidejte následující kód do .js
soubor:
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);
Jako obvykle forEach
prochází smyčkou přes numbers
pole a provedení funkce zpětného volání pro každý prvek. V tomto zpětném volání vše, co děláme, je aktualizace numbers
pole vynásobením jeho aktuálního iterovaného prvku číslem 2.
A na pole a jeho indexy odkazujeme pomocí arr[index]
.
Uložte soubor.
výstup:
[4, 8, 12, 16, 20]
Jdeme dál.
Použití druhého argumentu metody forEach – tj. thisValue
Někdy můžete pracovat s this
klíčové slovo ve vašem forEach
smyčka. A pokud toto klíčové slovo znáte, budete vědět, že může odkazovat na jiný objekt.
Chcete-li toto klíčové slovo spojit s vaším objektem zájmu, JavaScript forEach
nám poskytuje thisValue
argument, jak je uvedeno v jeho syntaxi.
Podívejme se na případ použití.
Začněte přidáním následujícího kódu do .js
soubor:
function MyNumber() {
this.data = [];
}
MyNumber.prototype.multiply = function () {
console.log("test");
}
const num = new MyNumber()
num.multiply();
Pokud jste někdy psali objektově orientovaný styl kódu, měli byste být obeznámeni s výše uvedeným.
Definovali jsme funkci konstruktoru MyNumber
obsahující data
vlastnost a multiply
metoda.
V tuto chvíli kód nic moc nedělá. Pokud jej uložíte a zkontrolujete konzoli, uvidíte pouze „testovací“ zprávu.
Nyní aktualizujme kód, abyste měli:
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);
Oblast zaměření je multiply
metoda. Jeho funkce přijímá pole jako argument, který procházíme pomocí forEach
metoda.
Logika je taková, že chceme aktualizovat prázdné data
pole vložením nových prvků pole do něj. Takže musíme odkazovat na data
vlastnost pomocí this
klíčové slovo v rámci zpětného volání.
Ale pokud soubor uložíte a podíváte se do konzole, uvidíte něco takového:
Kromě chyby konzoly se také zobrazuje Window
objekt, protože jsme console.log(this)
uvnitř forEach
.
To znamená, že this
odkazuje na globální objekt, kterým je Window
. Místo toho chceme this
odkazovat na aktuální instanci objektu.
Zde je druhý argument forEach
Stačí přidat this
jako argument a uložte soubor. Měl bys být dobrý.
numbers.forEach(function (number) {
console.log(this);
this.data.push(number * 2)
}, this)
Pokud konzoli znovu zkontrolujete, uvidíte, že this
nyní ukazuje na instanci objektu.
Výstup:
[4, 8, 12]
Použití funkce šipky jako zpětného volání
Můžete se vyhnout použití this
jako druhý parametr forEach
Pokud nahradíte její funkci zpětného volání funkcí šipky. Jako tak:
numbers.forEach((number) => {
console.log(this);
this.data.push(number * 2)
})
Uložte a otestujte svůj kód. Bude to fungovat, protože funkce šipky lexikálně váže this
hodnota – tj. hodnota this
klíčové slovo je určeno jeho kontextem nebo okolním rozsahem.
ForEach() vždy vrací hodnotu undefined
Na to musíte být opatrní, protože je snadné zapomenout. Pokud se pokusíte vrátit forEach
funkce, získáte undefined
hodnotu.
Uvidíme. Přidejte následující kód do .js
soubor.
let numbers = [2, 4, 6, 8, 10];
const myNum = numbers.forEach(number => {
return number * 2
})
console.log(myNum);
Jak můžete vidět, vracíme forEach
logiku a přiřazení výsledku do myNum
proměnná.
Pokud soubor uložíte a otevřete konzoli, zobrazí se undefined
hodnotu.
Pokud byste chtěli něco vrátit, použijte jinou metodu, jako je map(). Má podobnou definici jako forEach
.
Vezměme stejný kód a nahradíme forEach
s map
metoda takhle:
let numbers = [2, 4, 6, 8, 10];
const myNum = numbers.map(number => {
return number * 2
})
console.log(myNum);
Uložte soubor a znovu navštivte konzolu.
Výstup:
[4, 8, 12, 16, 20]
Na rozdíl od forEach()
, map()
metoda vrací nové pole obsahující výsledky volání funkce na každém prvku pole.
Práce s objekty podobnými poli
Pokud jste někdy pracovali s HTML DOM, měli byste být obeznámeni s metodami DOM, jako je getElementsByClassName()
, getElementsByTagName()
a querySelectorAll()
.
Tyto metody lze použít ke shromáždění hromady prvků v dokumentu. A buď vrátí HTMLCollection
nebo NodeList
(oba jsou objekty podobné poli).
V této části se dozvíte, jak tyto objekty iterovat pomocí forEach
.
Podívejme se na praktický příklad. Přidejte do svého .html
následující soubor:
<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>
Pokud se pokusíte získat všech li
prvky pomocí metod DOM, budete mít:
let itemsByClassName = document.getElementsByClassName('list-item')
console.log(itemsByClassName);
Výstup:
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
NEBO…
let itemsByQuerySelector = document.querySelectorAll('.list-item')
console.log(itemsByQuerySelector);
Výstup:
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
Z výstupu byste si mysleli, že jde o pole, protože tak vypadají (protože obsahují indexy a vlastnost length). Ale nejsou!
Oba HTMLCollection
a NodeList
jsou objekty, které vypadají jako pole, tedy Array-like objektů.
To znamená, že většina metod Array dostupných prostřednictvím Array.prototype.
nebude na nich k dispozici. Místo toho dědí metody z Object.prototype
.
Jak tedy můžeme použít forEach
pro procházení li
prvky?
Naštěstí NodeList
zdědí několik z těchto metod pole, z nichž forEach
je jedním z nich. Můžeme tedy iterovat NodeList
přímo pomocí forEach
metoda takhle:
let itemsByQuerySelector = document.querySelectorAll('.list-item')
itemsByQuerySelector.forEach(item => console.log(item.innerText))
Při zpětném volání zaznamenáváme vnitřní text pro každý z iterovaných prvků.
Výstup:
item1
item2
item3
item4
Pokud uděláte totéž s HTMLCollection
, zobrazí se tato chyba:
Uncaught TypeError: itemsByClassName.forEach is not a function
K procházení tohoto typu objektu podobného Array můžeme použít call()
metoda. To nám umožňuje použít metodu, která patří jinému objektu.
V našem případě chceme volat forEach
metoda dostupná na Array.prototype
a poté jej použijte na HTMLCollection
.
Váš kód by měl vypadat takto:
let itemsByClassName = document.getElementsByClassName('list-item')
Array.prototype.forEach.call(itemsByClassName, (item) => console.log(item.innerText))
Uložte a zkontrolujte konzolu. Měli byste mít stejný výstup.
Převod objektů podobných poli na pole
Alternativou k procházení objektů podobnými poli je nejprve je transformovat na pole. Můžeme použít metodu nazvanou Array.from()
nebo použijte Spread syntaxi (…
) za to.
Pojďme se rychle podívat.
let itemsByClassName = document.getElementsByClassName('list-item')
let itemsArray = Array.from(itemsByClassName)
console.log(itemsArray);
Je to docela přímočaré.
Výstup:
(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)
Výsledek je stejný, pokud použijete operátor spread takto:
let itemsByClassName = document.getElementsByClassName('list-item')
let itemsArray = [...itemsByClassName]
console.log(itemsArray);
Syntaxe rozprostření (…
) „rozšíří“ nebo rozšíří objekt podobný poli uvnitř hranatých závorek, [] z něj udělá správné pole.
Nyní můžete použít forEach
metodu přímo na poli.
Další příklad objektu podobného poli.
Než to shrneme, můžete se setkat s touto strukturou objektů podobných Array:
const arrayLike = {
0: 'item1',
1: 'item2',
2: 'item3',
length: 3
};
Na rozdíl od předchozího není tento typ iterovatelný a nemůžete použít syntaxi spreadu k převodu na pole. V tomto případě jednoduše použijete Array.from()
jako tak:
const newArray = Array.from(arrayLike)
console.log(newArray);
Výstup:
["item1", "item2", "item3"]
Odtud můžete zavolat forEach
metoda na výstupu pro procházení.
Nebo pokud chcete, jednoduše použijte dřívější metodu volání forEach
nepřímo pomocí call()
metoda takhle:
const arrayLike = {
0: 'item1',
1: 'item2',
2: 'item3',
length: 3
};
Array.prototype.forEach.call(arrayLike, (item) => console.log(item))
Pokud soubor uložíte a zkontrolujete konzoli, měli byste vidět své položky.
Závěr
Viděli jsme téměř všechny případy použití metody forEach. Od iterace přes jednoduché pole až po práci s objekty podobnými poli a téměř vše, co je mezi tím. Nyní byste měli být schopni jej použít ve svém projektu.
Pokud máte nějaké dotazy, dejte mi prosím vědět prostřednictvím sekce komentářů.
A pokud se vám tento návod líbí, snažte se ho sdílet na webu a sledujte mě na Twitteru pro další aktualizace.