Javascript kako dobiti nadređene elemente. DOM tehnike: elementi roditelj, dijete i susjed. Sprječavanje zadanih radnji

The za svakoga() metoda izvršava danu funkciju jednom za svaki element niza.

Izvor za ovaj interaktivni primjer pohranjen je u GitHub repozitorij. Ako želite doprinijeti projektu interaktivnih primjera, klonirajte https://github.com/mdn/interactive-examples i pošaljite nam zahtjev za povlačenje.

Sintaksa

arr .forEach(callback(currentValue [, index [, array]]) [, thisArg ])

Parametri

povratni poziv Funkcija koja se izvršava na svakom elementu. Prihvaća između jednog i tri argumenta: currentValue Trenutni element koji se obrađuje u nizu. index Opcijski Indeks currentValue u nizu. array Optional Pozvan je array forEach(). thisArg Izborna vrijednost koja se koristi kao this prilikom izvršavanja povratnog poziva.

Povratna vrijednost

Opis

forEach() poziva dostavljenu funkciju povratnog poziva jednom za svaki element u nizu uzlaznim redoslijedom. Ne poziva se za svojstva indeksa koja su izbrisana ili nisu inicijalizirana. (Za rijetke nizove, .)

povratni poziv se poziva s tri argumenta:

  1. vrijednost elementa
  2. indeks elementa
  3. objekt Array koji se prelazi

Ako je thisArg parametar dostavljen za forEach(), koristit će se kao povratna vrijednost ove vrijednosti. ThisArg vrijednost je u konačnici vidljiva povratnim pozivom i određuje se prema uobičajenim pravilima za određivanje this koje vidi funkcija.

Raspon elemenata koje obrađuje forEach() postavlja se prije prvog pozivanja povratnog poziva. Elementi koji se pridodaju nizu nakon početka poziva forEach() neće biti posjećeni povratnim pozivom. Ako se postojeći elementi niza promijene ili izbrišu, njihova vrijednost proslijeđena povratnom pozivu bit će vrijednost u trenutku kada ih forEach() posjeti; elementi koji su izbrisani prije posjeta se ne posjećuju. Ako se elementi koji su već posjećeni uklone (npr. pomoću shift()) tijekom iteracije, kasniji elementi će biti preskočeni. (Pogledajte ovaj primjer u nastavku.)

forEach() izvršava funkciju povratnog poziva jednom za svaki element niza; za razliku od map() ili reduce() uvijek vraća nedefiniranu vrijednost i ne može se ulančati. Tipičan slučaj upotrebe je izvršavanje nuspojava na kraju lanca.

forEach() ne mijenja niz na kojem je pozvan. (Međutim, povratni poziv to može učiniti)

Ne postoji način da se zaustavi ili prekine forEach() petlja osim izbacivanjem iznimke. Ako vam je potrebno takvo ponašanje, metoda forEach() je pogrešan alat.

Prijevremeni raskid može se postići sa:

Metode niza: every(), some(), find() i findIndex() testiraju elemente niza s predikatom koji vraća istinitu vrijednost kako bi se utvrdilo je li potrebno daljnje ponavljanje.

Primjeri

Nema operacije za neinicijalizirane vrijednosti (rijetki nizovi)

const arraySparse = let numCallbackRuns = 0 arraySparse.forEach(function(element)( console.log(element) numCallbackRuns++ )) console.log("numCallbackRuns: ", numCallbackRuns) // 1 // 3 // 7 // numCallbackRuns: 3 // komentar: kao što vidite vrijednost koja nedostaje između 3 i 7 nije pozvala funkciju povratnog poziva.

Pretvaranje for petlje u forEach

const items = ["item1", "item2", "item3"] const copy = // prije za (neka i = 0; i< items.length; i++) { copy.push(items[i]) } // after items.forEach(function(item){ copy.push(item) })

Ispis sadržaja niza

Bilješka: Kako biste prikazali sadržaj niza u konzoli, možete koristiti console.table() , koji ispisuje formatiranu verziju niza.

Sljedeći primjer ilustrira alternativni pristup, koristeći forEach().

Sljedeći kod bilježi redak za svaki element u nizu:

Function logArrayElements(element, index, array) ( console.log("a[" + index + "] = " + element) ) // Primijetite da je indeks 2 preskočen, budući da nema stavke na // toj poziciji u niz... .forEach(logArrayElements) // zapisnici: // a = 2 // a = 5 // a = 9

Koristeći thisArg

Sljedeći (izmišljeni) primjer ažurira svojstva objekta iz svakog unosa u nizu:

Funkcija Counter() ( this.sum = 0 this.count = 0 ) Counter.prototype.add = function(array) ( array.forEach(function(entry) ( this.sum += entry ++this.count ), this ) // ^---- Napomena ) const obj = new Counter() obj.add() obj.count // 3 obj.sum // 16

Budući da je thisArg parametar (this) dostavljen forEach() , prosljeđuje se povratnom pozivu svaki put kada se pozove. Povratni poziv ga koristi kao svoju this vrijednost.

Funkcija kopiranja objekta

Sljedeći kod stvara kopiju zadanog objekta.

Postoje različiti načini za stvaranje kopije objekta. Sljedeće je samo jedan način i predstavljeno je kako bi se objasnilo kako Array.prototype.forEach() radi pomoću ECMAScript 5 Object.* meta svojstvenih funkcija.

Funkcija copy(obj) ( const copy = Object.create(Object.getPrototypeOf(obj)) const propNames = Object.getOwnPropertyNames(obj) propNames.forEach(function(name) ( const desc = Object.getOwnPropertyDescriptor(obj, name) Object .defineProperty(copy, name, desc) )) return copy ) const obj1 = ( a: 1, b: 2 ) const obj2 = copy(obj1) // obj2 sada izgleda kao obj1

Ako se polje modificira tijekom iteracije, drugi elementi mogu biti preskočeni.

Sljedeći primjer bilježi "jedan", "dva", "četiri".

Kada unos koji sadrži vrijednost "two" is reached, the first entry of the whole array is shifted off-resulting in all remaining entries moving up one position. Because element "four" is now at an earlier position in the array, "three" will be skipped.!}

forEach() ne radi kopiju niza prije ponavljanja.

Neka riječi = ["jedan", "dva", "tri", "četiri"] words.forEach(function(word) ( console.log(word) if (word === "two") ( words.shift( ) ) )) // jedan // dva // četiri

Spljošti niz

Sljedeći primjer ovdje je samo u svrhu učenja. Ako želite spljoštiti niz pomoću ugrađenih metoda, možete koristiti Array.prototype.flat() (za koji se očekuje da će biti dio ES2019 i već je implementiran u nekim preglednicima).

/** * Sravnjuje proslijeđeni niz u jednodimenzionalnom nizu * * @params (niz) arr * @returns (niz) */ funkcija izravnati (arr) ( const rezultat = arr.forEach((i) => ( if (Niz. isArray(i)) ( result.push(...flatten(i)) ) else ( result.push(i) )) return result ) // Upotreba const problem = , 8, 9]] izravnaj(problem) / /

Napomena o korištenju obećanja ili asinkronih funkcija

let ratings = neka sum = 0 let sumFunction = async funkcija (a, b) ( return a + b ) ratings.forEach(async function(rating) ( sum = await sumFunction(sum, rating) )) console.log(sum) // Očekivani rezultat: 14 // Stvarni rezultat: 0

Tehnički podaci

Specifikacija Status Komentar
ECMAScript najnoviji nacrt (ECMA-262)
Nacrt
ECMAScript 2015 (6. izdanje, ECMA-262)
Definicija "Array.prototype.forEach" u toj specifikaciji.
Standard
ECMAScript 5.1 (ECMA-262)
Definicija "Array.prototype.forEach" u toj specifikaciji.
Standard Početna definicija. Implementirano u JavaScriptu 1.6.

Kompatibilnost preglednika

Tablica kompatibilnosti na ovoj stranici generirana je iz strukturiranih podataka. Ako želite doprinijeti podacima, pogledajte https://github.com/mdn/browser-compat-data i pošaljite nam zahtjev za povlačenje.

Ažurirajte podatke o kompatibilnosti na GitHubu

Radna površinaMobilniposlužitelj
KromRubFirefoxInternet ExplorerOperaSafariAndroid web-prikazChrome za AndroidFirefox za AndroidOpera za AndroidSafari na iOS-uSamsung InternetNode.js
za svakogaPuna podrška za Chrome 1Edge Potpuna podrška 12Firefox Puna podrška 1.5IE puna podrška 9Opera Potpuna podrška DaSafari puna podrška 3WebView Android Puna podrška ≤37Chrome Android Puna podrška 18Firefox Android Puna podrška 4Opera Android Puna podrška DaSafari iOS Potpuna podrška 1Samsung Internet Android Puna podrška 1.0nodejs Puna podrška Da
  • I. Ponavljanje preko realnih nizova
    1. forEach metoda i srodne metode
    2. za petlju
    3. Ispravno korištenje for...in petlje
    4. for...of petlja (implicitna upotreba iteratora)
    5. Eksplicitna uporaba iteratora
  • II. Ponavljanje preko objekata sličnih nizu
    1. Korištenje metoda za ponavljanje stvarnih nizova
    2. Pretvori u pravi niz
    3. Napomena o objektima vremena izvođenja

I. Ponavljanje preko realnih nizova

Trenutačno postoje tri načina za ponavljanje elemenata stvarnog niza:

  1. metoda Array.prototype.forEach ;
  2. klasična for petlja
  3. "ispravno" konstruirana for...in petlja.

Osim toga, uskoro, s dolaskom novog standarda ECMAScript 6 (ES 6), očekuju se još dvije metode:

  1. for...of petlja (implicitna upotreba iteratora);
  2. eksplicitna uporaba iteratora.

1. Metoda forEach i srodne metode

Ako je vaš projekt dizajniran da podržava značajke standarda ECMAScript 5 (ES5), možete koristiti jednu od njegovih inovacija - metodu forEach.

Primjer upotrebe:

Var a = ["a", "b", "c"]; a.forEach(funkcija(unos) ( konzola.log(unos); ));

Općenito, korištenje forEach zahtijeva povezivanje biblioteke emulacije es5-shim za preglednike koji izvorno ne podržavaju ovu metodu. To uključuje IE 8 i ranije, koji se još uvijek koriste na nekim mjestima.

Prednost forEach je u tome što nema potrebe za deklariranjem lokalnih varijabli za pohranjivanje indeksa i vrijednosti trenutnog elementa niza, budući da se automatski prosljeđuju funkciji povratnog poziva kao argumenti.

Ako ste zabrinuti zbog mogućih troškova povratnog poziva za svaki element, ne brinite i pročitajte ovo.

forEach je dizajniran za iteraciju kroz sve elemente niza, ali osim njega, ES5 nudi još nekoliko korisnih metoda za iteraciju kroz sve ili neke elemente plus izvođenje nekih radnji na njima:

  • svaki - vraća true ako za svaki element niza povratni poziv vraća vrijednost koja se može pretvoriti u true.
  • some - vraća true ako za barem jedan element niza povratni poziv vraća vrijednost koja se može pretvoriti u true.
  • filter - stvara novi niz koji uključuje one elemente izvornog niza za koje povratni poziv vraća true.
  • map - stvara novi niz koji se sastoji od vrijednosti vraćenih povratnim pozivom.
  • smanji - reducira niz na jednu vrijednost, primjenjujući povratni poziv na svaki element niza redom, počevši od prvog (može biti korisno za izračun zbroja elemenata niza i druge funkcije sažetka).
  • reduceRight - radi slično kao reduce, ali ponavlja elemente obrnutim redoslijedom.

2. Za petlju

Dobro staro za pravila:

Var a = ["a", "b", "c"]; var indeks; za (indeks = 0; indeks< a.length; ++index) { console.log(a); }

Ako je duljina niza konstantna tijekom cijele petlje, a sama petlja pripada odjeljku koda koji je kritičan za izvedbu (što je malo vjerojatno), tada možete upotrijebiti "optimalniju" verziju for koja pohranjuje duljinu niza :

Var a = ["a", "b", "c"]; var indeks, len; za (index = 0, len = a.length; index< len; ++index) { console.log(a); }

U teoriji, ovaj kod bi trebao raditi malo brže od prethodnog.

Ako redoslijed elemenata nije bitan, onda možete ići i dalje u smislu optimizacije i riješiti se varijable za pohranjivanje duljine niza, mijenjajući redoslijed pretraživanja obrnutim:

Var a = ["a", "b", "c"]; var indeks; za (index = a.length - 1; index >= 0; --index) ( console.log(a); )

Međutim, u modernim JavaScript motorima takve igre optimizacije obično ne znače ništa.

3. Ispravna uporaba petlje for...in

Ako vam se savjetuje da koristite for...in petlju, zapamtite da ponavljanje nizova nije ono za što je namijenjeno. Suprotno uobičajenom pogrešnom shvaćanju, petlja for...in ne ponavlja preko indeksa polja, već radije kroz nabrojiva svojstva objekta.

Međutim, u nekim slučajevima, kao što je ponavljanje preko rijetkih nizova, for...in može biti korisno, sve dok poduzmete mjere opreza, kao što je prikazano u primjeru ispod:

// a - rijetki niz var a = ; a = "a"; a = "b"; a = "c"; for (var ključ u a) ( if (a.hasOwnProperty(ključ) && /^0$|^d*$/.test(ključ) && ključ<= 4294967294) { console.log(a); } }

U ovom primjeru, dvije provjere se izvode pri svakoj iteraciji petlje:

  1. da niz ima vlastito svojstvo koje se zove ključ (nije naslijeđeno od svog prototipa).
  2. taj ključ je niz koji sadrži decimalni prikaz cijelog broja čija je vrijednost manja od 4294967294. Odakle dolazi zadnji broj? Iz definicije indeksa niza u ES5, koja pokazuje da je najveći indeks koji element u nizu može imati: (2^32 - 2) = 4294967294 .

Naravno, takve će provjere oduzeti nepotrebno vrijeme prilikom izvođenja petlje. Ali u slučaju rijetkog niza, ova metoda je učinkovitija od for petlje, jer se u ovom slučaju ponavljaju samo oni elementi koji su eksplicitno definirani u nizu. Dakle, u gornjem primjeru, izvršit će se samo 3 iteracije (za indekse 0, 10 i 10000) - naspram 10001 u for petlji.

Kako ne biste pisali tako glomazan kontrolni kod svaki put kada trebate iterirati kroz niz, možete ga napisati kao zasebnu funkciju:

Funkcija arrayHasOwnIndex(niz, ključ) ( return array.hasOwnProperty(ključ) && /^0$|^d*$/.test(ključ) && ključ<= 4294967294; }

Tada će tijelo petlje iz primjera biti značajno smanjeno:

Za (unesite a) ( if (arrayHasOwnIndex(a, ključ)) ( console.log(a); ) )

Gore razmotreni kontrolni kod je univerzalan, prikladan za sve slučajeve. No umjesto toga možete koristiti kraću verziju, iako formalno ne sasvim ispravnu, ali ipak prikladnu za većinu slučajeva:

Za (unesite a) ( if (a.hasOwnProperty(key) && String(parseInt(key, 10)) === ključ) ( console.log(a); ) )

4. For...of petlja (implicitna upotreba iteratora)

ES6, još uvijek u statusu nacrta, trebao bi uvesti iteratore u JavaScript.

Iterator je protokol koji implementira objekt koji definira standardni način za dobivanje niza vrijednosti (konačnih ili beskonačnih).
Objekt ima iterator ako definira next() metodu, funkciju bez argumenata koja vraća objekt s dva svojstva:

  1. gotovo (boolean) - istinito ako je iterator došao do kraja niza koji se može ponoviti. Inače je vrijednost lažna.
  2. vrijednost - definira vrijednost koju vraća iterator. Može biti nedefinirano (nedostaje) ako je svojstvo done istinito.

Mnogi ugrađeni objekti, uklj. pravi nizovi imaju iteratore prema zadanim postavkama. Najjednostavniji način korištenja iteratora na stvarnim nizovima je korištenje konstrukcije new for...of.

Primjer korištenja za...od:

Varval; var a = ["a", "b", "c"]; za (val od a) ( console.log(val); )

U gornjem primjeru, for...of petlja implicitno poziva iterator objekta Array da dobije svaku vrijednost niza.

5. Eksplicitna uporaba iteratora

Iteratori se također mogu koristiti eksplicitno, međutim, u ovom slučaju kod postaje mnogo kompliciraniji u usporedbi s for...of petljom. Izgleda otprilike ovako:

Var a = ["a", "b", "c"]; unos var; dok (!(entry = a.next()).done) ( console.log(entry.value); )

II. Ponavljanje preko objekata sličnih nizu

Osim pravih nizova, u JavaScriptu postoje i objekti nalik na niz . Ono što im je zajedničko sa stvarnim nizovima je da imaju svojstvo duljine i svojstva imenovana kao brojevi koji odgovaraju elementima niza. Primjeri uključuju DOM kolekcije NodeList i pseudoniz argumenata, dostupan unutar bilo koje funkcije/metode.

1. Korištenje metoda za ponavljanje stvarnih nizova

U najmanju ruku, većina, ako ne i sve, metode iteracije preko stvarnih nizova mogu se koristiti za iteraciju preko objekata sličnih nizovima.

For i for...in konstrukcije mogu se primijeniti na objekte slične nizu na potpuno isti način kao i na stvarne nizove.

forEach i druge metode Array.prototype također se primjenjuju na objekte slične nizu. Da biste to učinili, morate koristiti Function.call ili Function.apply.

Na primjer, ako želite primijeniti forEach na svojstvo childNodes objekta Node, učinili biste to ovako:

Array.prototype.forEach.call(node.childNodes, function(child) ( // učiniti nešto s objektom dijete));

Kako bi ovaj trik bio lakši za ponovno korištenje, možete deklarirati referencu na metodu Array.prototype.forEach u zasebnoj varijabli i koristiti je kao prečac:

// (pod pretpostavkom da je sav kod ispod u istom opsegu) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) ( // učiniti nešto s objektom dijete));

Ako objekt sličan nizu ima iterator, on se može koristiti eksplicitno ili implicitno za iteraciju preko objekta na isti način kao za stvarne nizove.

2. Pretvorite u pravi niz

Također postoji još jedan, vrlo jednostavan način za iteraciju preko objekta nalik nizu: pretvorite ga u pravi niz i koristite bilo koju od gore spomenutih metoda za iteraciju preko stvarnih nizova. Za pretvorbu možete koristiti generičku metodu Array.prototype.slice koja se može primijeniti na bilo koji objekt sličan nizu. To se radi vrlo jednostavno, kao što je prikazano u primjeru u nastavku:

Var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);

Na primjer, ako želite konvertirati kolekciju NodeList u stvarni niz, trebao bi vam kod otprilike ovaj:

Var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);

3. Napomena o objektima vremena izvođenja

Ako primijenite Array.prototype metode na runtime objekte (kao što su DOM kolekcije), tada trebate biti svjesni da nije zajamčeno da će ove metode ispravno raditi u svim runtime okruženjima (uključujući preglednike). To ovisi o ponašanju određenog objekta u određenom izvršnom okruženju, ili točnije, o tome kako je apstraktna operacija HasProperty implementirana u ovom objektu. Problem je u tome što sam standard ES5 dopušta mogućnost da se objekt loše ponaša s obzirom na ovu operaciju (vidi §8.6.2).

Stoga je važno testirati rad metoda Array.prototype u svakom runtime okruženju (pregledniku) u kojem planirate koristiti svoju aplikaciju.