Kaikki tavat iteroida taulukon läpi JavaScriptissä. Taulukot: Iterointimenetelmät Määritä, onko objekti tyhjä

Hei! Viimeisellä oppitunnilla tarkastelimme, mitä esineet ovat ja miksi niitä tarvitaan, ja tänään tarkastelemme kuinka käsitellä esineen ominaisuuksia ja kuinka itse lajitella kaikkia näitä ominaisuuksia. Näihin tarkoituksiin käytetään for..in-ominaisuussilmukkaa (voit lukea silmukoista JavaScriptissä).

Silmukka sisään.

Syntaksi:

For (näppäile obj) ( /* ... toiminnot obj:n kanssa ... */ )

For..in-silmukka iteroi peräkkäin obj-objektin ominaisuuksien läpi kirjoittaen kunkin ominaisuuden nimen avaimeen.

Muuttujan ilmoittaminen for-silmukassa (var-avain obj:ssa)

Tässä silmukassa voit ilmoittaa avainmuuttujan:

For (var key in menu1) ( // ... )

Katsotaanpa esimerkkiä objektin ominaisuuksien iteroinnista käyttämällä for...in silmukkaa:

Var menu = (leveys: 400, korkeus: 300, otsikko: "Valikko Oma" ); for (var key in menu) ( // tämä koodi toimii jokaiselle objektin ominaisuudelle // ..ja näyttää ominaisuuden nimen ja sen arvon vastaavasti alert("Key: " + key + " value: " + menu) ;)

Haluan kiinnittää huomionne siihen, että esimerkissä käytimme hakasulkeiden valikkoa. Tämä johtuu siitä, että jos tallennamme ominaisuuden nimen muuttujaan, voimme käyttää sitä vain hakasulkeilla, mutta emme pisteellä.

Loop for...of

Mukana on myös uusi silmukka objektien ja taulukoiden läpikulkua varten. Sen syntaksi on hyvin samanlainen kuin for...in -silmukan, mutta erona on, että se ei tulosta taulukon avaimia tai indeksejä, vaan sen arvoja. Tässä on esimerkki:

Var menu = (leveys: 400, korkeus: 300, otsikko: "Valikko Oma" ); for (valikon var key) ( // tämä koodi toimii jokaiselle objektin ominaisuudelle // ..ja näyttää ominaisuuden arvon vastaavasti alert("value: " + key +","); //400, 300, "Valikko Oma")

Objektin ominaisuuksien lukumäärä

Mutta entä jos sinun on tiedettävä objektin ominaisuuksien lukumäärä? Miten voin tehdä sen?

Valitettavasti tähän ongelmaan ei ole valmiita ratkaisuja.

Helpoin tapa on käydä ominaisuudet läpi ja laskea seuraavasti:

Var menu = (leveys: 400, korkeus: 300, otsikko: "Valikko Oma" ); var count = 0; for (var-näppäin valikossa) ( count++; ) alert("Ominaisuudet yhteensä: " + count);

Tulokset

  • Objektin ominaisuuksien iterointiin käytetään näppäinsilmukkaa: for (avain obj:ssa).

Tehtävät

Selvitä, onko objekti tyhjä

Luo funktio isEmptyObject(obj), joka palauttaa tosi, jos objektilla ei ole ominaisuuksia ja false, jos ominaisuus on vähintään yksi.

Sen pitäisi toimia näin:

Funktio isEmptyObject(obj) ( /* koodisi */ ) var obj = (); hälytys(isEmptyObject(obj)); // true obj["8:30"] = "nousu"; hälytys(isEmptyObject(obj)); // väärä

Laske kaikkien kohteen ominaisuuksien aritmeettinen keskiarvo

Siellä on palkkakohde palkoilla. Kirjoita koodi, joka näyttää kaikkien palkkojen aritmeettisen keskiarvon.
Jos objekti on tyhjä, tuloksen tulee olla 0.
Esimerkiksi.

12 maaliskuuta 2016

Nykyaikaisessa JavaScriptissä on niin sanottuja iterointimenetelmiä, joita käytetään iteroimaan taulukoiden läpi. Tässä opetusohjelmassa käsittelemme seuraavat menetelmät:

jokaiselle

.forEach()-menetelmää käytetään Hae joukko. Se kutsuu ns. takaisinsoittofunktiota, jonka avulla välitetään kolme parametria item, i, arr, jossa:

  • item — taulukon elementti;
  • i on taulukon sarjanumero;
  • arr on itse matriisi, joka tulisi iteroida.

Jotta tämän menetelmän käyttö olisi helpompi ymmärtää, harkitse esimerkkiä:

Var user=["admin","pass",31]; user.forEach(function(tuote,i,user)( alert("Tuotenumeron arvo " + i + " : " + nimike); ));

Tätä menetelmää voidaan käyttää tavallisen for-silmukan sijaan.

suodattaa

Suodattamiseen käytetään .filter()-menetelmää, se käyttää myös takaisinsoittotoimintoa, mutta luo uuden taulukon, jos taulukon elementit vastaavat arvoa true:

Var arr=; var newArr=arr.filter(function(number)( palauttaa numeron< 0; }); alert(newArr); // выведет -34,-4

Tässä esimerkissä numerot tarkistetaan negatiivisten arvojen varalta, ja tulos on uusi taulukko näillä arvoilla. Voit keksiä omat ehdot, näiden ei välttämättä tarvitse olla numeroita.

jokainen/jotkut

Nämä kaksi menetelmää ovat samankaltaisia ​​​​toistensa kanssa ja molempia käytetään taulukon tarkistamiseen, vain menetelmä .joka() palauttaa tosi, jos kaikki taulukon arvot vastaavat määritettyä ehtoa ja menetelmää .jonkin verran() palauttaa tosi, jos vähintään yksi arvo vastaa ehtoa:

Var arr=; alert(arr.every(function(number)( palauttaa numeron< 0; })); // выведет false

Toivon, että on selvää, että jos yllä olevassa esimerkissä käytimme jokin menetelmä silloin olisimme näyttäneet arvon tosi arvon false sijaan.

kartta

.map()-menetelmä muuttaa taulukon ja saa siitä uuden. Kaikki tehdään kutsumalla takaisinsoittotoiminto:

Var arr=; var newArr=arr.map(funktio(numero)(palautusnumero*2; )); hälytys(newArr);

Tässä esimerkissä saimme uuden taulukon, jossa on kaksinkertaiset elementtien arvot.

vähentää/vähentääOikea

Viimeiset menetelmät, joita tarkastelemme, ovat vähennys ja vähennysOikeus. Niitä käytetään taulukon jokaisen elementin käsittelemiseen samalla kun välitulos tallennetaan. Menetelmä toistuu jokaisen elementin läpi vasemmalta oikealle, reductionRight tekee päinvastoin. Toisin kuin muut menetelmät, takaisinkutsun lisäksi tässä määritellään myös inicial Value -argumentti - "alkuarvo". Lisäksi takaisinsoittotoiminto määrittää "välituloksen" - previousValue Ja nykyinen kohde— taulukon nykyinen elementti.

Katsotaanpa esimerkkiä:

Funktio getSums(arr) ( var tulos = ; if (!arr.length) palauttaa tuloksen; var totalSum = arr.reduceRight(function(sum, item) ( result.push(sum); paluusumma + nimike; )); tulos .push(totalSum); palauttaa tuloksen; ) alert(getSums()); // 1,3,6,10,15

Mitä tässä esimerkissä tapahtui? Olemme luoneet funktion, jonka avulla voimme saada uuden taulukon, jossa on aikaisempien summasta luotuja elementtejä. Lisäksi elementtien raportti tulee lopusta. Ja tässä on yksinkertaisempi esimerkki, jossa loin funktion, joka laskee taulukon elementtien summan:

Funktio getSum(arr) ( var tulos = arr.reduce(funktio(summa, virta) ( paluusumma + virta )); palauttaa tulos; ); hälytys(getSum()); Tunnisteet: 

  • 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 ajonaikaisista 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 takaisinsoitto 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 soveltamalla takaisinkutsua taulukon jokaiseen elementtiin vuorollaan, 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.

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(callback(nykyinen arvo [, indeksi [, taulukko]]) [, thisArg ]);

Parametrit

callback Toiminto, joka suoritetaan kullekin elementille kolmella argumentilla: currentValue Nykyinen taulukossa käsiteltävä elementti. index Valinnainen Matriisissa käsiteltävän nykyisen elementin indeksi. array Valinnainen Ary forEach() kutsuttiin. thisArg Valinnainen arvo, jota käytetään tähän takaisinkutsua suoritettaessa.

Palautusarvo

Kuvaus

forEach() kutsuu tarjotun takaisinkutsufunktion kerran jokaiselle taulukon elementille nousevassa järjestyksessä. Sitä ei vedota indeksiominaisuuksille, jotka on poistettu tai joita ei ole alustettu (eli harvassa taulukossa).

takaisinsoitto kutsutaan kolmella argumentilla:

  1. elementin arvo
  2. elementin indeksi
  3. ajettava Array-objekti

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

ForEach():n käsittelemien elementtien alue asetetaan ennen ensimmäistä takaisinkutsun kutsua. Elementit, jotka liitetään taulukkoon sen jälkeen, kun forEach()-kutsu on alkanut, takaisinsoitto ei käy. Jos olemassa olevia taulukon elementtejä muutetaan tai poistetaan, niiden takaisinkutsuun välitetty arvo on arvo, joka on ajankohdassa forEach() vierailee niissä; elementeissä, jotka on poistettu ennen vierailua, ei käytetä. Jos elementtejä, joissa on jo vierailtu, poistetaan (esim. Shift()) iteroinnin aikana, myöhemmät elementit ohitetaan - katso esimerkki alla.

forEach() suorittaa takaisinkutsun kerran kullekin taulukon elementille; toisin kuin map() tai vähentää(), se palauttaa aina arvon määrittelemättömänä eikä ole ketjutettavissa. Tyypillinen käyttötapaus on sivuvaikutusten suorittaminen ketjun lopussa.

forEach() ei mutatoi taulukkoa, jossa sitä kutsutaan (vaikka callback, jos sitä kutsutaan, voi tehdä niin).

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 // 7 // numCallbackRuns: 3 // 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 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 toista tapaa tehdä tämä 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 joukko. .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 += merkintä; ++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 käytettäväksi 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 se on esitetty selittämään, 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(function(nimi) ( const desc = Object.getOwnPropertyDescriptor(obj, nimi) Object.defineProperty(kopio, nimi, desc); )); palauttaa kopio; ) 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", "neljä". Kun merkintä sisältää arvon "two" is reached, the first entry of the whole array is shifted off, which results 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() does not make a copy of the array before iterating.!}

Muutt sanat = ["yksi", "kaksi", "kolme", ​​"neljä"]; sanat.forEach(funktio(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()-toimintoa (oletettavasti osa ES2019:ää ja 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) / /

Tekniset tiedot

Erittely Tila 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 JavaScript 1.6:ssa.

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 KylläEdge Täysi tuki 12Firefox Täysi tuki 1.5IE Täysi tuki 9Opera Täysi tuki KylläSafari Täysi tuki KylläWebView Android Täysi tuki KylläChrome Android Täysi tuki KylläFirefox Android Täysi tuki 4Opera Android Täysi tuki KylläSafari iOS Täysi tuki KylläSamsung Internet Android Täysi tuki Kyllänodejs Täysi tuki Kyllä

22 vastausta

Tämän testin suorittamisen jälkeen useimmilla nykyaikaisilla selaimilla...

Tällä hetkellä silmukan nopein muoto (ja mielestäni syntaktisesti ilmeisin).

vakiopituiselle välimuistissa olevalle silmukalle

For (var i = 0, len = myArray.length; i< len; i++) { }

Sanoisin, että tämä on ehdottomasti tapaus, jossa kiitän JavaScript-moottorien kehittäjiä. Suoritusaika on optimoitava selkeys, ei mukavuuden vuoksi.

Kesäkuussa 2016, useita testejä uusimmassa Chromessa (71 % selainmarkkinoista toukokuussa 2016 ja kasvussa):

  • Nopein sykli on syklin sykli, sekä välimuistin pituudella että ilman, mikä tarjoaa hyvin samanlaisen suorituskyvyn. (For-silmukka, jonka pituus on välimuistissa, tuottaa joskus parempia tuloksia kuin se, jota ei ole tallennettu välimuistiin, mutta ero on lähes olematon, mikä tarkoittaa, että moottori voidaan optimoida tavallisen ja ehkä yksinkertaisimman silmukan hyväksi ilman välimuistia).
  • Dekrementtien while-silmukka oli noin 1,5 kertaa hitaampi kuin for-silmukka.
  • Takaisinsoittotoimintoa käyttävä silmukka (esim. standardi forEach) oli noin 10 kertaa hitaampi kuin for-silmukka.

Uskon, että tämä säie on liian vanha, ja ohjelmoijat katsovat, että heidän on tallennettava pituus välimuistiin tai käytettävä taaksepäin pienentäviä risteyksiä paremman suorituskyvyn saavuttamiseksi, kirjoittamalla koodia, joka on vähemmän nirso ja virhealttiimpi kuin pelkkä for-silmukka. Siksi suosittelen:

    Jos sovelluksesi toistuu useiden elementtien läpi tai silmukkakoodisi on usein käytetyn funktion sisällä, suora silmukka on vastaus:

    For (var i = 0; i< arr.length; i++) { // Do stuff with arr[i] or i }

    Jos sovelluksesi ei todellakaan iteroi monista elementeistä tai sinun on vain tehtävä pieniä iteraatioita siellä täällä, tavallisen forEach-soittopyynnön tai minkä tahansa vastaavan JS-kirjastosi toiminnon käyttäminen voi olla puhtaampaa ja vähemmän virhealtista, koska hakemisto muuttujan laajuus on yksityinen ja sinun ei tarvitse käyttää sulkeita, jotka pääsevät suoraan taulukon arvoon:

    Arr.forEach(function(arvo, indeksi) ( // Tee asioita arvolla tai indeksillä ));

    Jos joudut todella sekoittelemaan muutaman millisekunnin, kun iteroit miljardeja rivejä, eikä taulukon pituus muutu prosessin aikana, voit harkita pituuden tallentamista välimuistiin for-silmukassa. Vaikka mielestäni se ei todellakaan ole välttämätöntä nykyään:

    For (var i = 0, len = arr.length; i< len; i++) { // Do stuff with arr[i] }

On vasta vuosi 2018, joten päivitys saattaa olla hyvä...

Ja minun todella pitäisi eri mieltä hyväksytyn vastauksen kanssa. Riippuu eri selaimista. jotkut tekevät forEachin nopeammin, jotkut for-loop ja jotkut samalla testaa kaikkia menetelmiä http://jsben.ch/mW36e

Arr.forEach(a => ( // ... )

ja koska voit nähdä paljon for(a = 0;...) silmukoita, kuten for(a = 0;...), on syytä mainita, että ilman muuttujia "var" määritellään globaalisti ja tällä voi olla merkittävä vaikutus nopeudella, joten se on hidasta.

var arr = arr = uusi Array(11111111).fill(255); var benches = [ [ "tyhjä", () =>< l; a++); }] , ["for-loop", () =>(for(var a = 0, l = arr.length; a< l; ++a) var b = arr[a] + 1; }] , ["for-loop++", () =>(for(var a = 0, l = arr.length; a< l; a++) var b = arr[a] + 1; }] , ["for-loop - arr.length", () =>(for(var a = 0; a< arr.length; ++a) var b = arr[a] + 1; }] , ["reverse for-loop", () =>(for(var a = arr.length - 1; a >= 0; --a) var b = arr[a] + 1; )] ,["while-loop", () => ( var a = 0 , l = arr.length; while(a< l) { var b = arr[a] + 1; ++a; } }] , ["reverse-do-while-loop", () =>( var a = arr.length - 1; // HUOLELLISESTI do ( var b = arr[a] + 1; ) while(a--); )] , ["forEach", () => ( arr.forEach( a => ( var b = a + 1; )); )], ["for..in (vain 3,3 %)", () => ( var ar = arr.slice(0,arr.length/33) ; for(const a in ar) ( var b = a + 1; ) )] , ["Duff-laite", () => ( var i = 0; var r = arr.length % 8; var n = (arr .length - r) / 8; if (r > 0) do ( var b = arr + 1; ) while (--r); if (n > 0) do ( var b = arr[i] + 1; var c = arr + 1; var d = arr + 1; var e = arr + 1; var f = arr + 1; var g = arr + 1; var h = arr + 1; var k = arr + 1; i = --n >>> 3; ) while (n); )] , ["Duff laite negatiivinen", () => ( var r = arr.length % 8; var n = (arr.length-r) / 8 ; ///Math.floor(arr.length / 8); var i = arr.length ; // -1; while(r)( var b = arr[--i] + 1; --r; ) while (n)( var b = arr[i] + 1; var c = arr + 1; var d = arr + 1; var e = arr + 1; var f = arr + 1; var g = arr + 1; var h = arr + 1; var j = arr + 1; i = -n >>> 3; ) )]]; function bench(title, f) ( var t0 = performance.now(); var res = f(); return performance.now() - t0; // console.log("$(title) kesti $(t1-t0 ) msec"); ) var globalVarTime = bench("for-silmukka ilman "var"", () => ( // Jos unohdat laittaa "var", niin muuttujat"ovat globaaleja for(a = 0, l =arr.length;a< l; ++a) var b = arr[a] + 1; }); var times = benches.map(function(a) { arr = new Array(11111111).fill(255); return }).sort((a,b) =>a-b); var max = kertaa; kertaa = kertaa.map(a => (a = (a/max)*100; return a; )); var template = (nimi, aika, n) => "

" + "$(otsikko) " + " $(Number(aika.Kiinteä(3)))ms" + "
"; var strRes = times.map(t => malli(...t)).join("\n") + "

for-loop ilman "var" $(globalVarTime) msec."; var $container = document.getElementById("container"); $container.innerHTML = strRes; body ( color:#fff; background:#333; font-family :helvetica; ) body > div > div ( selkeä: molemmat ) body > div > div > span ( float:left; leveys:43%; margin:3px 0; text-align:right; ) body > div > div > span :nth-child(2) ( text-align:left; background:tummarange; animation:showup .37s .111s; -webkit-animation:showup .37s .111s; ) @keyframes showup ( from ( leveys:0; ) ) @-webkit-keyframes ilmestyy ( from ( leveys:0; ) )

2014 Joskus sitten

Ajattele loogisesti.

Katso tätä

For(muuttujaindeksi = 0 , pituus = array.length ; indeksi< length ; index++) { //do stuff }

  • Sinun on luotava vähintään 2 muuttujaa (indeksi, pituus)
  • Tarkasta, onko pituusilmaisin pienempi kuin
  • Indeksiä pitää nostaa
  • for-silmukassa on 3 parametria

Kerro nyt miksi tämän pitäisi olla nopeampi kuin:

Muuttujan pituus = array.length; while(--length) ( //tai pituus-- //tee juttuja)

  • Yksi muuttuja
  • Ei shekkejä
  • indeksi laskee (koneet suosivat tätä)
  • Vaikka sillä on vain yksi parametri

Olin täysin hämmentynyt, kun Chrome 28 osoitti, että for-silmukka oli aikaa nopeampi. Sen pitäisi olla jotain sellaista

"No, kaikki käyttävät for-silmukkaa, keskitytään siihen, kun käytetään kromia."

Mutta nyt vuonna 2014 while-silmukka palaa kromiin. se on 2x nopeampi, muissa/vanhoissa selaimissa se oli aina nopeampi.

Olen tehnyt uusia testejä viime aikoina. Nyt todellisessa envoirement-maailmassa nämä lyhytkoodit ovat arvottomia, eikä jsperf voi itse asiassa suorittaa while-silmukkaa oikein, koska sen on luotava uudelleen array.length, mikä myös vie aikaa.

EI VOI saada jsperfin while-silmukan todellista nopeutta.

sinun on luotava oma funktio ja tarkistettava se komennolla window.performance.now()

Ja kyllä... ei ole mitään keinoa hetkeksi silmukalle olla nopeampi.

Todellinen ongelma on todellinen manipulointi / toistoaika / piirustusaika tai miksi haluat sitä kutsua.

Esimerkiksi minulla on kangaskohtaus, jossa minun täytyy laskea koordinaatit ja törmäykset... tämä tehdään 10-200 mikrosekuntia (ei millisekuntia). kaiken tekemiseen kuluu useita millisekunteja. Sama kuin DOM:ssa.

On toinenkin erittäin tehokas tapa käyttää silmukkaa joissakin tapauksissa... esimerkiksi kopioida/kloonata taulukko

For(var i = array.length; i > 0; arrayCopy[ --i ] = array[ i ] // tekee asioita);

Huomioi parametriasetukset:

  • Sama kuin while-silmukassa. Käytän vain yhtä muuttujaa
  • Sinun on tarkistettava, onko indeksi suurempi kuin 0;
  • Kuten näette, tämä lähestymistapa eroaa tavallisesta kaikkien käyttämästä silmukasta, koska teen asioita 3. parametrin sisällä ja myös pienentän suoraan taulukon sisällä.

Sanotaan, että tämä vahvistaa, että koneet, kuten

kirjoitti, että ajattelin lyhentää sitä hieman ja poistaa turhat tavarat ja kirjoitti tämän samalla tyylillä:

For(var i = array.length ; i-- ; arrayCopy[ i ] = array[ i ] // tekee asioita);

Vaikka se on lyhyempi, näyttää siltä, ​​​​että i:n käyttö taas hidastaa kaikkea. Tämä on 1/5 hitaampi kuin edellinen for- ja while-silmukka.

Huomautus:; erittäin tärkeä jälkeen for looo ilman ()

Vaikka sanoin juuri, että jsperf ei ole paras tapa testata skriptejä. Olen lisännyt tähän 2 silmukkaa.

Ja tässä on toinen vastaus suorituskyvystä javascriptissä

Tämän vastauksen pitäisi näyttää tehokkaita tapoja kirjoittaa JavaScript. Joten jos et voi lukea tätä, kysy ja saat vastauksen tai lue javascriptiä käsittelevä kirja http://www.ecma-international.org/ecma-262/5.1/

Valmistamani testin viimeisin versio (käyttämällä uudelleen vanhempaa) osoittaa yhden asian.

Välimuistin pituus ei ole niin tärkeä, mutta se ei haittaa.

Jokainen yllä linkitetyn testin ensimmäinen ajo (äskettäin avatussa välilehdessä) antaa parhaat tulokset neljälle viimeiselle fragmentille (3., 5., 7. ja 10. kaavioissa) Chromessa, Operassa ja Firefoxissa 64-bittisessä Debian Squeezessäni ( työpöytälaitteistoni). Seuraavat ajot antavat täysin erilaisen tuloksen.

Toiminnan johtopäätökset ovat yksinkertaiset:

  • Siirry for-silmukkaan (eteenpäin) ja tarkista sen sijaan !==< .
  • Jos taulukkoa ei tarvitse käyttää uudelleen myöhemmin, on myös tehokas silmukka, jonka pituus on lyhennetty ja jossa on tuhoisa array shift() -ing.

Tällä hetkellä (2011.10) alla oleva malli näyttää olevan nopein.

For (var i = 0, len = arr.length; i !== len; i++) ( ... )

Muista, että välimuistiin tallentaminen arr.length ei ole kriittinen tässä, joten voit vain testata i !== arr.length ja suorituskykyä ei tule, mutta saat lyhyemmän koodin.

PS: Tiedän, että fragmentissa, jossa on shift() sen tulosta voidaan käyttää 0:nnen elementin sijaan, mutta jotenkin unohdin sen, että kun käytin uudelleen edellistä versiota (jolla oli väärä arvo silmukoiden aikana), ja myöhemmin en halunnut menettää jo saavutetut tulokset.

"Paras" kuin puhtaassa suorituskyvyssä? tai suorituskykyä JA?

Puhdas "paras" suorituskyky on se, joka käyttää välimuistia ja ++-etuliiteoperaattoria (tietoni: http://jsperf.com/caching-array-length/189)

For (var i = 0, len = myArray.length; i< len; ++i) { // blah blah }

Sanoisin, että välimuistiton silmukka on paras tasapaino suoritusajan ja ohjelmoijan lukuajan välillä. Jokainen C/C++/Javalla alkava ohjelmoija ei kuluta ms:ää tämän lukemiseen

For(var i=0; i< arr.length; i++){ // blah blah }

** välimuistiin taulukon pituus silmukan sisällä, muutama sekunti aikaa lipsahtaa pois. Riippuu taulukon elementeistä, jos taulukossa on enemmän elementtejä, on suuri ero Ms-ajan suhteen*

SArr; //Matriisi; for(var i = 0 ; i

SArr; //Matriisi; for(var i = 0,len = sArr.length ; i< len ; i++) { callArray(sArr[i]); //function call } ***end: 1.354ms***

Tämä on vuosi 2017 .

Tein joitain testejä.

Näyttää siltä, ​​että while-menetelmä on nopein Chromessa.

Näyttää siltä, ​​että vasen dekrementti (--i) on paljon nopeampi kuin muut (++i , i--, i++) Firefoxissa.

Tämä lähestymistapa on keskimäärin paasto. Mutta se toistaa taulukon käänteisessä järjestyksessä.

Olkoon i = array.length; while (--i >= 0) ( doSomething(array[i]); )

Jos tärkeysjärjestys on tärkeä, käytä tätä lähestymistapaa.

Olkoon ii = array.length; olkoon i = 0; sillä aikaa kun minä< ii) { doSomething(array[i]); ++i; }

Kirjoitan aina ensimmäisellä tyylillä.

Vaikka kääntäjä on tarpeeksi älykäs optimoimaan sen taulukoita varten, mutta onko se silti fiksua, jos käytämme tässä DOMNodeListiä tai jotain monimutkaista objektia, jolla on laskettu pituus?

Tiedän, että kysymys koskee taulukoita, mutta mielestäni on hyvä käytäntö kirjoittaa kaikki silmukat samalla tyylillä.

Var arr = ; // Taulukko var i = 0; sillä aikaa kun minä< arr.length) { // Do something with arr[i] i++; }

i++ on nopeampi kuin ++i, --i ja i -