Javascript kuinka saada vanhempi elementtejä. DOM-tekniikat: vanhempi-, lapsi- ja naapurielementit. Oletustoimintojen estäminen

The jokaiselle () menetelmä suorittaa tarjotun funktion kerran kullekin taulukon elementille.

Tämän interaktiivisen esimerkin lähde on tallennettu GitHub-tietovarastoon. Jos haluat osallistua interaktiivisten esimerkkien projektiin, kloonaa https://github.com/mdn/interactive-examples ja lähetä meille vetopyyntö.

Syntaksi

arr .forEach(takaisinkutsu(nykyinen arvo [, indeksi [, taulukko]]) [, thisArg ])

Parametrit

takaisinsoitto Toiminto, joka suoritetaan jokaiselle elementille. Se hyväksyy yhdestä kolmeen argumenttia: currentValue Nykyinen taulukossa käsiteltävä elementti.

index Valinnainen Indeksi currentValue taulukossa.

array Valinnainen Ary forEach() kutsuttiin.

thisArg Valinnainen arvo, jota käytetään tähän takaisinkutsua suoritettaessa.

Palautusarvo

  1. Kuvaus
  2. forEach() kutsuu tarjotun takaisinkutsufunktion kerran jokaiselle taulukon elementille nousevassa järjestyksessä. Sitä ei vedota indeksiominaisuuksille, jotka on poistettu tai joita ei ole alustettu. (Harvoille ryhmille.)
  3. takaisinsoitto kutsutaan kolmella argumentilla:

elementin arvo

elementin indeksi

ajettava Array-objekti

Jos thisArg-parametri annetaan forEach() -parametrille, sitä käytetään takaisinkutsun arvona. Tämä Arg-arvo on viime kädessä havaittavissa takaisinkutsun avulla määritetään tavallisten sääntöjen mukaisesti, jotka koskevat funktion näkemän tämän määrittämistä.

ForEach()-silmukkaa ei voi pysäyttää tai katkaista muuten kuin heittämällä poikkeus. Jos tarvitset tällaista toimintaa, forEach()-menetelmä on väärä työkalu.

Ennenaikainen irtisanominen voidaan suorittaa seuraavasti:

Taulukkomenetelmät: every() , some() , find() ja findIndex() testaavat taulukon elementtejä predikaatilla, joka palauttaa totuudenmukaisen arvon määrittääkseen, tarvitaanko lisäiteraatioita.

Esimerkkejä

Ei toimintoa alustamattomille arvoille (harvat taulukot)

const arraySparse = anna numCallbackRuns = 0 arraySparse.forEach(function(element)( console.log(element) numCallbackRuns++ )) console.log("numCallbackRuns: ", numCallbackRuns) // 1 // 3 // allback //uns num:C 3 R // kommentti: kuten näet, puuttuva arvo välillä 3 ja 7 ei kutsunut takaisinsoittotoimintoa.

For-silmukan muuntaminen forEachiksi

const items = ["tuote1", "tuote2", "tuote3"] const kopio = // ennen for (olkoon i = 0; i< items.length; i++) { copy.push(items[i]) } // after items.forEach(function(item){ copy.push(item) })

Taulukon sisällön tulostaminen

Huomautus: Voit näyttää taulukon sisällön konsolissa käyttämällä console.table() -komentoa, joka tulostaa muotoillun version taulukosta.

Seuraava esimerkki havainnollistaa vaihtoehtoista lähestymistapaa käyttämällä forEach() -funktiota.

Seuraava koodi kirjaa rivin jokaiselle taulukon elementille:

Funktio logArrayElements(elementti, index, array) ( console.log("a[" + index + "] = " + element) ) // Huomaa, että indeksi 2 ohitetaan, koska // siinä paikassa ei ole alkiota array... .forEach(logArrayElements) // lokit: // a = 2 // a = 5 // a = 9

Käyttämällä tätäArg

Seuraava (kehitetty) esimerkki päivittää objektin ominaisuudet jokaisesta taulukon merkinnästä:

Funktio Counter() ( this.sum = 0 this.count = 0 ) Counter.prototype.add = function(array) ( array.forEach(function(entry) ( this.sum += entry ++this.count ), tämä ) // ^---- Huomautus ) const obj = new Counter() obj.add() obj.count // 3 obj.sum // 16

Koska thisArg-parametri (this) annetaan forEach() -parametrille, se välitetään takaisinkutsulle joka kerta, kun sitä kutsutaan. Takaisinsoitto käyttää sitä tämän arvona.

Objektin kopiointitoiminto

Seuraava koodi luo kopion tietystä objektista.

On olemassa erilaisia ​​tapoja luoda kopio objektista. Seuraava on vain yksi tapa, ja sen tarkoituksena on selittää, kuinka Array.prototype.forEach() toimii käyttämällä ECMAScript 5 Object.* -metaominaisuusfunktioita.

Funktio copy(obj) ( const copy = Object.create(Object.getPrototypeOf(obj)) const propNames = Object.getOwnPropertyNames(obj) propNames.forEach(funktio(nimi) ( const desc = Object.getOwnPropertyDescriptor(obj, name) Object .defineProperty(kopio, nimi, desc) )) return copy ) const obj1 = ( a: 1, b: 2 ) const obj2 = kopioi(obj1) // obj2 näyttää nyt obj1:ltä

Jos taulukkoa muokataan iteraation aikana, muut elementit voidaan ohittaa.

Seuraava esimerkki kirjaa "yksi" , "kaksi" ja "neljä" .

Kun merkintä sisältää arvon "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() ei tee kopiota taulukosta ennen iterointia.

Olkoon sanat = ["yksi", "kaksi", "kolme", ​​"neljä"] words.forEach(function(sana) ( console.log(word) if (sana === "kaksi") ( words.shift( ) ) )) // yksi // kaksi // neljä

Tasoita taulukko

Seuraava esimerkki on vain oppimistarkoituksessa. Jos haluat litistää taulukon sisäänrakennetuilla menetelmillä, voit käyttää Array.prototype.flat()-komentoa (jonka odotetaan olevan osa ES2019:ää, ja se on jo toteutettu joissakin selaimissa).

/** * Tasoittaa välitetyn taulukon yksiulotteisessa taulukossa * * @params (array) arr * @returns (array) */ funktio flatten(arr) ( const result = arr.forEach((i) => (if (Matriisi. isArray(i)) ( result.push(...flatten(i)) ) else ( result.push(i) )) return result ) // Usage const problem = , 8, 9]] flatten(problem) / /

Huomautus Promises- tai async-funktioiden käytöstä

anna arvosanat = anna summa = 0 anna summaFunction = async function (a, b) ( palauttaa a + b ) ratings.forEach(async function(rating) ( summa = odota summaFunction(sum, rating) )) console.log(sum) // Odotettu tulos: 14 // Todellinen lähtö: 0

Tekniset tiedot

Erittely Status Kommentti
ECMAScriptin uusin luonnos (ECMA-262)
Luonnos
ECMAScript 2015 (6. painos, ECMA-262)
"Array.prototype.forEach" määritelmä kyseisessä määrittelyssä.
Vakio
ECMAScript 5.1 (ECMA-262)
"Array.prototype.forEach" määritelmä kyseisessä määrittelyssä.
Vakio Alkuperäinen määritelmä. Toteutettu JavaScriptissä 1.6.

Selaimen yhteensopivuus

Tämän sivun yhteensopivuustaulukko on luotu strukturoiduista tiedoista. Jos haluat osallistua tietoihin, katso https://github.com/mdn/browser-compat-data ja lähetä meille vetopyyntö.

Päivitä GitHubin yhteensopivuustiedot

TyöpöytämobiiliPalvelin
KromiReunaFirefoxInternet ExplorerOopperaSafariAndroid-verkkonäkymäChrome AndroidilleFirefox AndroidilleOpera AndroidilleSafari iOS:ssäSamsung InternetNode.js
jokaiselleChrome Täysi tuki 1Edge Täysi tuki 12Firefox Täysi tuki 1.5IE Täysi tuki 9Opera Täysi tuki KylläSafari Täysi tuki 3WebView Android Täysi tuki ≤37Chrome Android Täysi tuki 18Firefox Android Täysi tuki 4Opera Android Täysi tuki KylläSafari iOS Täysi tuki 1Samsung Internet Android Täysi tuki 1.0nodejs Täysi tuki Kyllä
  • I. Iterointi todellisten taulukoiden yli
    1. jokaiselle menetelmälle ja siihen liittyville menetelmille
    2. silmukalle
    3. For...in silmukan oikea käyttö
    4. for... of loop (implisiittinen iteraattorin käyttö)
    5. Iteraattorin selkeä käyttö
  • II. Iterointi taulukon kaltaisten objektien yli
    1. Menetelmien käyttö todellisten taulukoiden iterointiin
    2. Muunna todelliseksi taulukoksi
    3. Huomautus suorituksenaikaisista objekteista

I. Iterointi todellisten taulukoiden yli

Tällä hetkellä on kolme tapaa iteroida todellisen taulukon elementtejä:

  1. menetelmä Array.prototype.forEach ;
  2. klassikko silmukalle
  3. "oikein" rakennettu...silmukalle.

Lisäksi pian, uuden ECMAScript 6 (ES 6) -standardin myötä, odotetaan kahta muuta menetelmää:

  1. for...of silmukan (implisiittinen iteraattorin käyttö);
  2. iteraattorin eksplisiittinen käyttö.

1. ForEach-menetelmä ja siihen liittyvät menetelmät

Jos projektisi on suunniteltu tukemaan ECMAScript 5 (ES5) -standardin ominaisuuksia, voit käyttää yhtä sen innovaatioista - forEach-menetelmää.

Käyttöesimerkki:

Var a = ["a", "b", "c"]; a.forEach(funktio(merkintä) ( console.log(merkintä); ));

Yleensä forEachin käyttö edellyttää es5-shim-emulointikirjaston yhdistämistä selaimille, jotka eivät tue tätä menetelmää. Näitä ovat IE 8 ja aiemmat versiot, jotka ovat edelleen käytössä paikoin.

ForEachin etuna on, että paikallisia muuttujia ei tarvitse ilmoittaa nykyisen taulukkoelementin indeksin ja arvon tallentamiseksi, koska ne välitetään automaattisesti takaisinsoittofunktiolle argumentteina.

Jos olet huolissasi kustakin elementistä takaisinsoittojen mahdollisista kustannuksista, älä huoli ja lue tämä.

forEach on suunniteltu iteroimaan kaikki taulukon elementit, mutta sen lisäksi ES5 tarjoaa useita hyödyllisiä menetelmiä kaikkien tai joidenkin elementtien iterointiin sekä joidenkin toimien suorittamiseen niille:

  • every - palauttaa tosi , jos jokaiselle taulukon elementille takaisinkutsu palauttaa arvon , joka voidaan muuntaa tosi .
  • jotkut - palauttaa tosi, jos vähintään yhdelle taulukon elementille takaisinkutsu palauttaa arvon, joka voidaan muuntaa tosiksi.
  • suodatin - luo uuden taulukon, joka sisältää ne alkuperäisen taulukon elementit, joille takaisinsoitto palauttaa tosi.
  • kartta - luo uuden taulukon, joka koostuu takaisinkutsun palauttamista arvoista.
  • vähentää - pienentää taulukon yhdeksi arvoksi ja soveltaa takaisinkutsua jokaiseen taulukon elementtiin vuorotellen alkaen ensimmäisestä (voi olla hyödyllinen taulukon elementtien ja muiden yhteenvetofunktioiden summan laskemisessa).
  • vähentääRight - toimii samalla tavalla kuin pelkistys, mutta toistuu elementtien läpi käänteisessä järjestyksessä.

2. Silmukalle

Vanha hyvä säännöille:

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

Jos taulukon pituus on vakio koko silmukan ajan ja silmukka itse kuuluu suorituskykykriittiseen koodin osaan (mikä on epätodennäköistä), voit käyttää "optimaalisempaa" versiota, joka tallentaa taulukon pituuden. :

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

Teoriassa tämän koodin pitäisi toimia hieman nopeammin kuin edellinen.

Jos elementtien järjestys ei ole tärkeä, voit mennä vielä pidemmälle optimoinnin suhteen ja päästä eroon muuttujasta taulukon pituuden tallentamiseksi muuttamalla haun järjestystä päinvastaiseksi:

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

Nykyaikaisissa JavaScript-moottoreissa tällaiset optimointipelit eivät kuitenkaan yleensä tarkoita mitään.

3. For...in silmukan oikea käyttö

Jos sinua kehotetaan käyttämään for...in-silmukkaa, muista, että taulukoiden iterointi ei ole sitä, mihin se on tarkoitettu. Vastoin yleistä väärinkäsitystä, for...in -silmukka ei iteroi taulukkoindeksien, vaan objektin lukuisten ominaisuuksien kautta.

Joissakin tapauksissa, kuten iterointi harvassa taulukossa, for...in voi kuitenkin olla hyödyllistä, kunhan noudatat varotoimia, kuten alla olevassa esimerkissä näkyy:

// a - harva matriisi var a = ; a = "a"; a = "b"; a = "c"; for (var key in a) ( if (a.hasOwnProperty(avain) && /^0$|^d*$/.test(avain) && avain<= 4294967294) { console.log(a); } }

Tässä esimerkissä silmukan jokaisessa iteraatiossa suoritetaan kaksi tarkistusta:

  1. että taulukolla on oma ominaisuus nimeltä avain (ei peritty sen prototyypistä).
  2. tämä avain on merkkijono, joka sisältää desimaaliesityksen kokonaisluvusta, jonka arvo on pienempi kuin 4294967294. Mistä viimeinen numero tulee? ES5:n taulukkoindeksin määritelmästä, joka osoittaa, että korkein indeksi, joka taulukon elementillä voi olla, on: (2^32 - 2) = 4294967294 .

Tietenkin tällaiset tarkistukset vievät turhaa aikaa silmukkaa suoritettaessa. Mutta harvan taulukon tapauksessa tämä menetelmä on tehokkaampi kuin for-silmukka, koska tässä tapauksessa vain ne elementit, jotka on määritelty taulukossa, iteroidaan. Joten yllä olevassa esimerkissä suoritetaan vain 3 iteraatiota (indekseille 0, 10 ja 10000) verrattuna 10001:een for-silmukassa.

Jotta et kirjoita niin hankalaa tarkistuskoodia joka kerta, kun sinun on iteroitava taulukon läpi, voit kirjoittaa sen erillisenä funktiona:

Funktio arrayHasOwnIndex(taulukko, avain) ( return array.hasOwnProperty(avain) && /^0$|^d*$/.test(avain) && avain<= 4294967294; }

Sitten esimerkin silmukan runko pienenee merkittävästi:

For (näppäin a) ( if (arrayHasOwnIndex(a, avain)) ( console.log(a); ) )

Yllä käsitelty tarkistuskoodi on universaali, sopii kaikkiin tapauksiin. Mutta sen sijaan voit käyttää lyhyempää versiota, vaikkakaan ei muodollisesti täysin oikeaa, mutta joka kuitenkin sopii useimpiin tapauksiin:

For (key in a) ( if (a.hasOwnProperty(avain) && String(parseInt(avain, 10)) === avain) ( console.log(a); ) )

4. For...of silmukan (iteraattorin implisiittinen käyttö)

ES6, joka on edelleen luonnostilassa, tuo iteraattorit JavaScriptiin.

Iteraattori on objektin toteuttama protokolla, joka määrittää vakiotavan arvosarjan (äärellisen tai äärettömän) saamiseksi.
Objektilla on iteraattori, jos se määrittää next()-metodin, ei-argumenttifunktion, joka palauttaa objektin, jolla on kaksi ominaisuutta:

  1. tehty (boolean) - tosi, jos iteraattori on saavuttanut iteroitavan sekvenssin lopun. Muuten arvo on väärä.
  2. arvo - määrittää iteraattorin palauttaman arvon. Voi olla määrittelemätön (puuttuu), jos tehty ominaisuus on tosi .

Monet sisäänrakennetut esineet, mm. todellisissa taulukoissa on oletuksena iteraattorit. Yksinkertaisin tapa käyttää iteraattoria todellisissa taulukoissa on käyttää uutta for...of -konstruktiota.

Esimerkki käytöstä:

Varval; var a = ["a", "b", "c"]; for (arvo of a) ( console.log(val); )

Yllä olevassa esimerkissä for...of-silmukka kutsuu implisiittisesti Array-objektin iteraattoria saadakseen taulukon jokaisen arvon.

5. Iteraattorin eksplisiittinen käyttö

Iteraattoreita voidaan käyttää myös eksplisiittisesti, mutta tässä tapauksessa koodista tulee paljon monimutkaisempi verrattuna for...of-silmukkaan. Se näyttää jotakuinkin tältä:

Var a = ["a", "b", "c"]; var pääsy; while (!(merkintä = a.seuraava()).tehty) ( console.log(entry.value); )

II. Iterointi taulukon kaltaisten objektien yli

Oikeiden taulukoiden lisäksi JavaScriptissä on myös taulukon kaltaisia ​​objekteja . Niillä on yhteistä todellisten taulukoiden kanssa, että niillä on pituusominaisuus ja ominaisuudet, jotka on nimetty numeroiksi, jotka vastaavat taulukon elementtejä. Esimerkkejä ovat NodeList-kokoelman DOM ja argumentit pseudo-array, jotka ovat käytettävissä missä tahansa funktiossa/menetelmässä.

1. Menetelmien käyttö todellisten taulukoiden iterointiin

Vähintään useimpia, ellei kaikkia, todellisten taulukoiden iterointimenetelmiä voidaan käyttää taulukon kaltaisten objektien iterointiin.

For ja for...in -konstrukteja voidaan soveltaa taulukon kaltaisiin objekteihin täsmälleen samalla tavalla kuin niitä sovelletaan todellisiin taulukoihin.

forEach ja muut Array.prototype-menetelmät koskevat myös taulukon kaltaisia ​​objekteja. Tätä varten sinun on käytettävä Function.call tai Function.apply .

Jos esimerkiksi haluat soveltaa forEach-komentoa Node-objektin childNodes-ominaisuuteen, teet sen seuraavasti:

Array.prototype.forEach.call(node.childNodes, function(child) ( // tee jotain aliobjektilla));

Tämän tempun uudelleenkäytön helpottamiseksi voit ilmoittaa viittauksen Array.prototype.forEach-metodiin erillisessä muuttujassa ja käyttää sitä pikakuvakkeena:

// (olettaen, että kaikki alla oleva koodi on samassa laajuudessa) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) ( // tee jotain aliobjektilla));

Jos taulukon kaltaisella objektilla on iteraattori, sitä voidaan käyttää eksplisiittisesti tai implisiittisesti iteroimaan objektin yli samalla tavalla kuin todellisissa taulukoissa.

2. Muunna todelliseksi taulukoksi

On myös toinen, hyvin yksinkertainen tapa iteroida taulukon kaltaisen objektin yli: muuntaa se todelliseksi taulukoksi ja käyttää mitä tahansa edellä käsitellyistä menetelmistä iteroitaessa todellisia taulukoita. Muuntamiseen voit käyttää yleistä Array.prototype.slice-menetelmää, jota voidaan soveltaa mihin tahansa taulukon kaltaiseen objektiin. Tämä tehdään hyvin yksinkertaisesti, kuten alla olevassa esimerkissä näkyy:

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

Jos esimerkiksi haluat muuntaa NodeList-kokoelman varsinaiseksi taulukoksi, tarvitset seuraavanlaisen koodin:

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

3. Huomautus ajonaikaisista objekteista

Jos käytät Array.prototype-menetelmiä ajonaikaisiin objekteihin (kuten DOM-kokoelmiin), sinun tulee olla tietoinen siitä, että näiden menetelmien ei voida taata toimivan oikein kaikissa ajonaikaisissa ympäristöissä (mukaan lukien selaimet). Tämä riippuu tietyn objektin käyttäytymisestä tietyssä suoritusympäristössä tai tarkemmin sanottuna siitä, kuinka abstrakti operaatio HasProperty on toteutettu tässä objektissa. Ongelmana on, että ES5-standardi itsessään sallii objektin virheellisen toiminnan tämän toiminnon suhteen (katso §8.6.2).

Siksi on tärkeää testata Array.prototype-menetelmien toiminta jokaisessa ajonaikaisessa ympäristössä (selaimessa), jossa aiot käyttää sovellustasi.