Za svaki niz u javascript?

Kako mogu pregledati sve unose u nizu pomoću javascripta?

Mislio sam da je nešto ovako:

 forEach(instance in theArray) 

Gdje je theArray moj niz, ali izgleda pogrešno.

4041
17 февр. Dante1986 postavljen je 17. veljače 2012-02-17 16:51 '12 u 16:51 2012-02-17 16:51
@ 32 odgovora
  • 1
  • 2

TL; DR

  • Ne koristite for-in ako ga ne koristite sa zaštitom ili barem ne znate zašto vas može ugristi.
  • Vaše najbolje oklade su obično

    • petlja for-of (samo za ES2015 +),
    • Array#forEach ( spec MDN ) (ili some njegove rodbine i slično) (samo ES5 +)
    • jednostavna staromodna for petlje,
    • ili ulaz for-in ulaz s zaštitom.

Ali još ima puno toga za istražiti, pročitajte na ...


JavaScript ima moćnu semantiku za cikličko pretvaranje polja i objekata niza. Odgovor sam podijelio u dva dijela: opcije za autentične nizove i opcije za stvari koje su slične samo nizovima, kao što su objekt arguments , drugi iterabilni objekti (ES2015 +), DOM zbirke, itd.

Brzo primijetim da sada možete koristiti ES2015 opcije, čak i na ES5 motorima, slanjem ES2015 na ES5. Nađi "ES2015 transpiling" / "ES6 transpiling" za više ...

Pogledajte naše opcije:

Za stvarne nizove

Imate tri opcije u ECMAScript 5 ("ES5"), trenutno najpopularniju verziju i još dvije u ECMAScript 2015 ("ES2015", "ES6"):

  1. Upotrijebi forEach i povezane (ES5 +)
  2. Koristite jednostavnu petlju
  3. Ispravno koristite for-in
  4. Koristi for-of (koristi implicitni iterator) (ES2015 +)
  5. Izričito upotrijebite iterator (ES2015 +)

pojedinosti:

1. Koristite za forEach i srodne

U bilo kojem neograničenom modernom okruženju (dobro, ne u IE8), gdje imate pristup Array funkcijama koje je dodao ES5 (izravno ili pomoću polipolnih ispuna), možete koristiti forEach ( spec | MDN ):

 var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); }); 

forEach prihvaća funkciju povratnog poziva i, opcionalno, vrijednost koja se koristi na this prilikom pozivanja ovog povratnog poziva (ne koristi se gore). Povratni poziv se poziva za svaki unos u nizu za preskakanje nepostojećih unosa u rijetkim nizovima. Iako sam koristio samo jedan argument gore, povratni poziv se zove s tri: vrijednost svakog zapisa, indeks tog zapisa i veza na polje koje ponavljate (u slučaju da ga vaša funkcija već nema).

Ako ne podržavate naslijeđene preglednike, kao što je IE8 (koji prikazuje NetApps na više od 4% tržišta u vrijeme pisanja ovog dokumenta u rujnu 2016.), možete sretno koristiti za forEach na univerzalnoj web stranici bez izgleda stranice. Ako trebate podržavati zastarjele preglednike, lako je izvršiti shimming / polyfilling za forEach operaciju (pronađite "es5 shim" za nekoliko opcija).

forEach ima prednost da ne morate deklarirati indeksiranje i vrijednosti varijabli u području sadržaja, jer se oni isporučuju kao argumenti za funkciju iteracije i tako dobro usmjereni na ovu iteraciju.

Ako ste zabrinuti oko vremena koje je potrebno za izvršenje poziva funkcije za svaki zapis niza, nemojte biti; pojedinosti .

Osim toga, za forEach je forEach "petlja kroz sve", ali je ES5 definirala nekoliko drugih korisnih "elaboracija kroz funkcije polja i stvari", uključujući:

  • every (zaustavlja petlju prilikom prvog povratnog poziva koji vraća false ili nešto pogrešno)
  • some (zaustavlja petlju kada se povratni poziv vraća true ili je nešto uvjerljivo)
  • filter (stvara novi niz koji uključuje elemente u kojima funkcija filtra vraća true i izostavlja one gdje vraća false )
  • map (stvara novi niz povratnih vrijednosti povratnog poziva)
  • reduce (povećava vrijednost, ponovno poziva na povratni poziv, prosljeđuje prethodne vrijednosti, vidi specifikaciju za detalje, korisno za zbrajanje sadržaja niza i mnoge druge stvari)
  • reduceRight (na primjer, reduce , ali radi u opadajućem redoslijedu, ne rastućim redoslijedom)

2. Koristite jednostavnu petlju

Ponekad su stari načini najbolji:

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

Ako se duljina niza ne mijenja tijekom ciklusa, a njegova izvedba je osjetljivi kod (malo vjerojatno), nešto kompliciranija verzija snimanja s prednjom duljinom može biti nešto brža:

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

I / ili odbrojavanje:

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

Ali s modernim mehanizmima JavaScripta, rijetko morate iskopati ovaj posljednji sok.

U ES2015 i novijim varijablama indeksa i vrijednosti možete napraviti lokalnu vrijednost for petlje:

 let a = ["a", "b", "c"]; for (let index = 0; index < a.length; ++index) { let value = a[index]; } //console.log(index); // Would cause "ReferenceError: index is not defined" //console.log(value); // Would cause "ReferenceError: value is not defined" 

A kada to učinite, ne samo da se value već i index ponovno kreiraju za svaku iteraciju petlje, tj. Zaporke stvorene u oznaci petlje sadrže referencu na index (i value ) stvorenu za tu određenu iteraciju:

 let divs = document.querySelectorAll("div"); for (let index = 0; index < divs.length; ++index) { divs[index].addEventListener('click', e => { alert("Index is: " + index); }); } 

Ako ste imali pet divova, dobili biste "Indeks je: 0", ako ste kliknuli prvi i "Indeks je: 4", ako ste kliknuli posljednji. To ne radi ako koristite var umjesto let .

3. Ispravno koristite for-in .

Dobit ćete ljude koji će vam reći da koristite for-in , ali to nije ono što for-in za . for-in piše kroz nabrojana svojstva objekta, a ne indeksne matrice. Narudžba nije zajamčena , čak ni u ES2015 (ES6). ES2015 ne određuje redoslijed svojstava objekta (pomoću [[OwnPropertyKeys]] , [[Enumerate]] i stvari koje ih koriste kao Object.getOwnPropertyKeys ), ali ne navodi da će for-in slijediti taj redoslijed. (Detalji u ovom drugom odgovoru .)

Međutim, to može biti korisno, posebno za rijetke nizove , ako koristite odgovarajuće mjere opreza:

 // 'a' is a sparse array var key; var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (key in a) { if (a.hasOwnProperty(key)  // These are explained /^0$|^[1-9]\d*$/.test(key)  // and then hidden key <= 4294967294 // away below ) { console.log(a[key]); } } 

Zabilježite dvije provjere:

  1. Da objekt ima svoju vlastitu imovinu pod tim imenom (a ne onu koja je naslijedila od svog prototipa), i

  2. Da je ključ brojčani niz u osnovnom nizu u uobičajenom obliku, a njegova vrijednost je <= 2 ^ 32 - 2 (što je 4,294,967,294). Odakle dolazi taj broj? To je dio definicije indeksa niza u specifikaciji . Ostali brojevi (ne-cijeli brojevi, negativni brojevi, brojevi veći od 2 ^ 32 - 2) nisu indeksi polja. Uzrok 2 ^ 32 - 2 je ono što čini najvišu vrijednost indeksa manju od 2 ^ 32 - 1 , što je maksimalna vrijednost length polja. (Primjerice, duljina niza odgovara 32-bitnom nepotpisanom integeru.) (Potvrda od RobG-a da u komentaru na moj blog objavi da moj prethodni test nije bio posve ispravan).

Ovo je maleni dodatni dodatak za svaku iteraciju petlji na većini nizova, ali ako imate oskudni niz, to može biti učinkovitiji način za petlju, jer to su samo petlje za zapise koji zapravo postoje. Na primjer, za gornji niz, petlju pet puta (za tipke "0" , "10" i "10000" - zapamtite, to su linije), a ne 10,001 puta.

Sada je ne želite pisati svaki put, tako da ga možete staviti u svoj alat:

 function arrayHasOwnIndex(array, prop) { return array.hasOwnProperty(prop)  /^0$|^[1-9]\d*$/.test(prop)  prop <= 4294967294; // 2^32 - 2 } 

I onda ćemo je koristiti ovako:

 for (key in a) { if (arrayHasOwnIndex(a, key)) { console.log(a[key]); } } 

Ili, ako vas zanima samo test "dovoljno dobar za većinu slučajeva", možete ga koristiti, ali dokle god je blizu, to nije sasvim točno:

 for (key in a) { // "Good enough" for most cases if (String(parseInt(key, 10)) === key  a.hasOwnProperty(key)) { console.log(a[key]); } } 

4. Koristite for-of (koristite implicitni iterator) (ES2015 +)

ES2015 dodaje iteratore u JavaScript. Najjednostavniji način korištenja iteratora je novi operater. Izgleda ovako:

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

zaključak:

 b c

Pod poklopcima, koji dobivaju iterator iz niza i prolaze kroz njega, dobivaju se vrijednosti iz njega. Nema problema s korištenjem for-in ina, jer koristi iterator definiran objektom (nizom), a nizovi određuju da njihovi iteratori ponavljaju svoje zapise (a ne njihova svojstva). Za razliku od for-in u ES5, redoslijed kojim se pregledavaju zapisi je numerički poredak njihovih indeksa.

5. Izričito upotrijebite iterator (ES2015 +)

Ponekad možete eksplicitno koristiti iterator. I vi to možete učiniti, iako je puno lakše nego for-of . Izgleda ovako:

 var a = ["a", "b", "c"]; var it = a.values(); var entry; while (!(entry = it.next()).done) { console.log(entry.value); } 

Iterator je objekt koji odgovara definiciji Iteratora u specifikaciji. Njegov next način vraća novi objekt rezultata svaki put kada ga nazovete. Rezultat objekt ima svojstvo, done , govori nam je li to učinjeno, i value svojstva s vrijednošću za ovu iteraciju. ( done opcionalno ako bi bilo false , value nije obavezna ako nije undefined ).

value ovisi o iteratoru; nizovi podržavaju (barem) tri funkcije koje vraćaju iteratore:

  • values() : Ovo je ono što sam gore koristio. Vraća iterator, gdje je svaka value niz matrica za ovu iteraciju ( "a" , "b" i "c" u gornjem primjeru).
  • keys() : Vraća iterator, gdje je svaka value ključ za ovu iteraciju (tako će za našu gore biti "0" , a zatim "1" , a zatim "2" ).
  • entries() : vraća iterator, gdje je svaka value niz u obliku [key, value] za ovu iteraciju.

Za objekte poput niza

Osim pravih nizova, postoje i objekti nalik na nizove koji imaju svojstvo length i svojstva s numeričkim imenima: NodeList instance, objekt arguments , itd. Kako možemo NodeList njihov sadržaj?

Za nizove koristite bilo koji od gore navedenih parametara.

Barem neki, a možda i većina ili čak svi gore navedeni nizovi često se jednako dobro koriste za objekte tipa niza:

  1. Upotrijebi forEach i povezane (ES5 +)

    Različite funkcije na Array.prototype su "namjerno generičke" i obično se mogu koristiti za objekte poput niza putem Function#call Function#apply ili Function#apply . (Pogledajte Odricanje od odgovornosti za objekte koje je host na kraju ovog odgovora, ali to je rijedak problem.)

    Pretpostavimo da želite koristiti forEach u childNodes Node childNodes . To biste učinili:

     Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with 'child' }); 

    Ako ćete to učiniti puno, možda ćete poželjeti dobiti kopiju reference funkcije u varijabli koja će se ponovno upotrijebiti, na primjer:

     // (This is all presumably in some scoping function) var forEach = Array.prototype.forEach; // Then later... forEach.call(node.childNodes, function(child) { // Do something with 'child' }); 
  2. Koristite jednostavnu petlju

    Očito, jednostavna petlja se primjenjuje na objekte poput niza.

  3. Ispravno koristite for-in

    for-in s istim jamstvima kao i s nizom, trebao bi raditi s objektima sličnim nizu; Rezervacije mogu biti potrebne za stavke koje je domaćin dao na broj 1 gore.

  4. Koristi for-of (koristi implicitni iterator) (ES2015 +)

    for-of će koristiti iterator koji daje objekt (ako ga ima); morat ćemo vidjeti kako se to događa s raznim objektima nalik na polje, osobito s host datotekama. Na primjer, specifikacija za NodeList iz querySelectorAll ažurirana kako bi podržala iteraciju. Specifikacija za HTMLCollection od getElementsByTagName nije.

  5. Izričito upotrijebite iterator (ES2015 +)

    Pogledajte broj 4, moramo vidjeti kako se iteratori razvijaju.

Stvorite pravi niz

U drugim slučajevima, objekt poput polja možete pretvoriti u pravi niz. Da biste to učinili iznenađujuće je jednostavno:

  1. Koristite metodu slice array

    Možemo koristiti metodu slice array, koja je, kao i ostale gore spomenute metode, "namjerno generički" i stoga se može koristiti s objektima nalik na niz, na primjer:

     var trueArray = Array.prototype.slice.call(arrayLikeObject); 

    Na primjer, ako želimo pretvoriti NodeList u pravi niz, možemo to učiniti:

     var divs = Array.prototype.slice.call(document.querySelectorAll("div")); 

    U nastavku pogledajte "Oprez za objekte koje pruža domaćin". Konkretno, imajte na umu da to neće raditi u IE8 i ranijim verzijama, što ne dopušta korištenje objekata koje pruža domaćin na this .

  2. Koristi distribucijsku sintaksu ( ... )

    Također je moguće koristiti ES2015 distribucijsku sintaksu s JavaScript mehanizmima koji podržavaju ovu značajku:

     var trueArray = [...iterableObject]; 

    Tako, na primjer, ako želimo pretvoriti NodeList u pravi niz, s propagacijskom sintaksom, postaje vrlo kratak:

     var divs = [...document.querySelectorAll("div")]; 
  3. Koristite Array.from (spec) | (MDN)

    Array.from (ES2015 +, ali jednostavno ispunjen poli) stvara niz od nekog objekta kao što je polje, ako je potrebno, prvo propušta zapise kroz funkciju podudaranja. pa:

     var divs = Array.from(document.querySelectorAll("div")); 

    Ili, ako želite dobiti niz naziva oznaka za elemente s danom klasom, morate koristiti funkciju mapiranja:

     // Arrow function (ES2015): var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName); // Standard function (since 'Array.from' can be shimmed): var divs = Array.from(document.querySelectorAll(".some-class"), function(element) { return element.tagName; }); 

Oprez za objekte koje pruža domaćin

Ako koristite funkcije Array.prototype s objektima kao što su hostovi (DOM popisi i druge stvari koje pruža preglednik, a ne JavaScript mehanizam), morate provjeriti u ciljnim okruženjima da biste se uvjerili da se pruženi host objekt ponaša je točno. Većina se ponaša ispravno (sada), ali važno je provjeriti. Razlog tome je što se većina metoda Array.prototype koje vjerojatno želite koristiti oslanjaju na objekt koji daje host, dajući iskren odgovor na sažetak [[HasProperty]] . U vrijeme pisanja ovog teksta, preglednici su to jako dobro obavili, ali je u specifikaciji 5.1 predloženo da objekt koji je dao domaćin možda nije pošten. Ovo je u 8.6.2 , nekoliko paragrafa ispod velike tablice na početku ovog odjeljka, gdje piše:

Objekti domaćini mogu implementirati ove interne metode na bilo koji način, osim ako nije drugačije naznačeno; na primjer, jedna mogućnost je da [[Get]] i [[Put]] za određeni host objekt doista dohvaćaju i spremaju vrijednosti svojstava, ali [[HasProperty]] uvijek generira false .

(Nisam mogao pronaći ekvivalentnu formulaciju u specifikaciji ES2015, ali još uvijek mora biti.) Opet, kao i kod pisanja zajedničkog hosta danog niza tipova objekata u modernim preglednicima [ NodeList instance, na primjer], učinite da [[HasProperty]] rukuje ispravno, ali provjeriti).

6292
17 февр. Odgovor daje TJ Crowder 17. veljače. 2012-02-17 16:53 '12 u 4:53 pm 2012-02-17 16:53

Uredi : ovaj odgovor je beznadno zastario. Za moderniji pristup pogledajte metode dostupne u nizu . Metode od interesa mogu biti:

  • za svaki
  • karta
  • filtar
  • zatvarač
  • smanjiti
  • svaki
  • malo

Standardni način ponavljanja niza u JavaScriptu je for -loop vanilija:

border=0
 var length = arr.length, element = null; for (var i = 0; i < length; i++) { element = arr[i]; // Do something with element } 

Napominjemo, međutim, da je ovaj pristup dobar samo ako imate gust niz, a svaki indeks zauzima element. Ako je niz je rijedak, onda s ovim pristupom svibanj izvoditi u probleme s performansama, jer ćete proći kroz mnogo indeksa koji zapravo ne postoje u polje. U ovom slučaju, bolje je koristiti for.. in lop. Međutim, morate upotrijebiti odgovarajuće mjere opreza kako biste osigurali da su na for..in samo potrebna svojstva polja (tj. Elementi niza), jer će se for..in -opolje također navesti u naslijeđenim preglednicima ili ako su dodatna svojstva definirana kao enumerable .

U ECMAScript 5 metoda forEach koristit će se za prototip niza, ali nije podržana u starijim preglednicima. Stoga, da biste ga mogli koristiti dosljedno, morate imati okruženje koje ga podržava (na primjer, Node.js za JavaScript na strani poslužitelja) ili koristiti "Polyfill". Međutim, Polyfill za ovu funkcionalnost je trivijalan, i budući da kod čini lakšim za čitanje, trebao bi biti uključen u Polyfill.

470
17 февр. Odgovor dao PatrikAkerstrand 17. veljače. 2012-02-17 16:55 '12 u 4:55 pm 2012-02-17 16:55

Ako koristite knjižnicu jQuery , možete koristiti jQuery.each :

 var length = yourArray.length; for (var i = 0; i < length; i++) { // Do something with yourArray[i]. } 
214
17 февр. Odgovor je dat Poonam 17. veljače. 2012-02-17 17:01 '12 u 17:01 2012-02-17 17:01

Povucite natrag

Mislim da obratno za taj ciklus ovdje treba spomenuti:

 for (var i = array.length; i--; ) { // process array[i] } 

prednosti:

  • Ne trebate deklarirati privremenu varijablu len ili je usporediti s array.length na svakoj iteraciji, što može biti minuta optimizacije.
  • Uklanjanje braće i sestara iz DOM-a obrnutim redoslijedom obično je učinkovitije . (Preglednik mora premjestiti manje elemenata u unutarnja polja.)
  • Ako promijenite niz tijekom petlje, na ili nakon indeksa I (na primjer, izbrišete ili umetnete element u array[i] ), izravna petlja preskače element koji je pomaknut ulijevo na položaj i ili ponovno provjerava i-ti element koji je pomaknut desno. U tradicionalnoj petlji, možete ažurirati i ukazati na sljedeći element koji treba obraditi - 1, ali jednostavno mijenjanje smjera iteracije često je jednostavnije i elegantnije rješenje .
  • Slično tome, kod promjene ili brisanja ugniježđenih DOM elemenata, obrnuta obrada može zaobići pogreške . Na primjer, razmislite o promjeni innerHTML nadređenog čvora prije obrade njegove djece. Do trenutka kada se dostigne dječji čvor, on će biti odvojen od DOM-a, zamjenjujući ga novim potomkom kada je napisana nadređena innerHTML.
  • kraći i pročitani od nekih drugih dostupnih opcija. Iako gubi za forEach() i za ES6 for ... of .

nedostaci:

  • Obrađuje stavke obrnutim redoslijedom. Если вы строили новый массив из результатов или печатали на экране, естественно вывод будет отменен относительно исходного порядка.
  • Неоднократно вставляя братьев и сестер в DOM в качестве первого ребенка, чтобы сохранить их порядок, менее эффективен . (В браузере все равно придется перекладывать вещи.) Чтобы создавать узлы DOM эффективно и упорядоченно, просто переходите вперед и добавьте как обычно (а также используйте "фрагмент документа" ).
  • Обратный цикл запутывает для младших разработчиков. (Вы можете считать это преимущество, в зависимости от вашего прогноза.)

Должен ли я всегда использовать его?