Kiekvienam „javascript“ masyvui?

Kaip peržiūrėti visus masyvo įrašus naudojant „JavaScript“?

Maniau, kad tai buvo kažkas panašaus:

 forEach(instance in theArray) 

Kur „ theArray yra mano masyvas, bet atrodo neteisinga.

4041
17 февр. Dante1986 nustatytas vasario 17 d 2012-02-17 16:51 '12 at 16:51 PM 2012-02-17 16:51
@ 32 atsakymai
  • 1
  • 2

Tl; DR

  • Nenaudokite for-in jei nenaudojate su apsauga arba bent jau nežinote, kodėl jis gali užkasti jus.
  • Jūsų geriausi statymai paprastai yra

    • kilpa (tik ES2015 +),
    • Array#forEach ( spec | MDN ) (arba some ir jų giminaičių) (tik ES5 +)
    • paprastas senamadiškas kilpoms,
    • arba for-in input su apsauga.

Tačiau vis dar yra daug ką ištirti, skaityti ...


„JavaScript“ turi galingą semantiką, skirtą masyvo tipų ir objektų cikliniam transformavimui. Atsakymą aš padalijau į dvi dalis: autentiškų masyvų parinktis ir variantus dalykams, kurie yra panašūs tik į matricas, pvz., arguments objektą, kitus pasikartojančius objektus (ES2015 +), DOM rinkinius ir kt.

Greitai pastebiu, kad dabar galite naudoti ES2015 parinktis net ir ES5 varikliuose, siunčiant ES2015 į ES5. Raskite „ES2015 transpiling“ / „ES6 transpiling“ daugiau ...

Na, pažvelkite į mūsų parinktis:

Tikrosioms masyvams

ECMAScript 5 („ES5“), šiuo metu plačiausiai remiamoje versijoje yra trys parinktys, o dar du - „ ECMAScript 2015“ („ES2015“, „ES6“):

  1. Naudokite forEach ir susijusius (ES5 +)
  2. Naudokite paprastą kilpą
  3. Tinkamai naudokite for-in
  4. Naudoti „ for-of (naudoti netiesioginį iteratorių) (ES2015 +)
  5. Naudokite iteratorių aiškiai (ES2015 +)

Išsami informacija:

1. Naudokite forEach ir susijusius

Bet kurioje neterminuotoje aplinkoje (gerai, ne IE8), kur jūs turite prieigą prie „ES5“ pridėtų „ Array funkcijų (tiesiogiai arba naudojant polipų užpildus), galite naudoti bet forEach ( spec | MDN ):

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

forEach priima atgalinio ryšio funkciją ir, pasirinktinai, šiam atšaukimui (anksčiau nenaudotam) naudojama tokia reikšmė. Kiekvienam masyvo įrašui skambinama, jei norite praleisti neegzistuojančius retų masyvų įrašus. Nors naudoju tik vieną aukščiau pateiktą argumentą, atšaukimas vadinamas trimis: kiekvieno įrašo reikšmė, šio įrašo rodyklė ir nuoroda į masyvą, kurį kartojate (jei jūsų funkcija dar neturi).

Jei nepalaikote senųjų naršyklių, pvz., IE8 (kurią „NetApps“ parodo daugiau nei 4% rinkos 2016 m. Rugsėjo mėn. Šio rašymo metu), jūs galite laimingai naudoti visuotinį tinklalapį be puslapio išdėstymo. Jei jums reikia palaikyti pasenusias naršykles, lengva atlikti „Shimm“ / „ forEach operaciją forEach operacijai (rasti „es5 shim“ kelioms parinktims).

forEach turi pranašumą, kad turinio srityje nereikia deklaruoti indeksavimo ir kintamųjų verčių, nes jos pateikiamos kaip argumentai iteracijos funkcijai ir yra taip gerai orientuoti į šią iteraciją.

Jei esate susirūpinęs dėl laiko, kurio reikia kiekvienam masyvo įrašo funkcijų skambučiui įvykdyti, nėra; informacija

Be to, „ forEach yra „kilpa per juos visus“ funkcija, tačiau ES5 apibrėžė keletą kitų naudingų „kūrinių, naudojant masyvo funkcijas ir dalykus“, įskaitant:

  • every (sustabdo kilpą pirmą kartą, kai grįžtamasis ryšys grąžina false ar kažką klaidingo)
  • some (sustabdo kilpą pirmą kartą, kai grįžtamasis ryšys grąžinamas true arba kažkas tikėtina)
  • filter (sukuria naują masyvą, apimantį elementus, kuriuose filtro funkcija grąžina true ir praleidžia tuos, kuriuose jis grąžina false )
  • map (sukuria naują grįžimo atgalinio ryšio reikšmių grupę)
  • reduce (didinant vertę, pakartotinai skambinant atgal, praeinant ankstesnes vertes, išsamesnės informacijos ieškokite specifikacijoje, naudinga sumaišyti masyvo turinį ir daugelį kitų dalykų)
  • reduceRight (pavyzdžiui, reduce , bet veikia mažėjančia tvarka, o ne didėjančia tvarka)

2. Naudokite paprastą kilpą

Kartais geriausi yra seni būdai:

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

Jei masyvo ilgis ciklo metu nepasikeičia, o jo veikimas yra jautrus kodas (mažai tikėtinas), šiek tiek sudėtingesnė užfiksavimo versija su priekiniu ilgiu gali būti šiek tiek greičiau:

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

Ir (arba) suskaičiuoti:

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

Tačiau su šiuolaikiniais „JavaScript“ mechanizmais retai turite išpjauti šią paskutinę sulčių dalį.

ES2015 ir naujesnėse versijose galite nustatyti, kad jūsų indeksas ir vertės kintamieji būtų lokalūs for kilpas:

 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" 

O kai tai padarysite, kiekviena ciklo iteracija atkuriama ne tik value bet ir index , ty, kilpos, sukurtos kilpos žymoje, turi nuorodą į index (ir value ), sukurtą šiam konkrečiam iteracijai:

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

Jei turėtumėte penkis skirtumus, „Indeksas yra: 0“, jei spustelėjote pirmą ir „Rodyklė: 4“, jei spustelėjote paskutinį. Tai neveikia, jei naudojate var o ne let .

3. Tinkamai naudokite for-in .

Jūs gausite žmonių, kurie jums pasakys, kad naudosite for-in , bet tai ne tas for-in prisijungti . for-in rašomas per išvardytas objekto savybes, o ne masyvo indeksus. Užsakymas negarantuojamas net ir ES2015 (ES6). ES2015 nustato objekto savybių eiliškumą (naudojant [[OwnPropertyKeys]] , [[OwnPropertyKeys]] ir dalykus, kurie juos naudoja kaip Object.getOwnPropertyKeys ), tačiau nenurodo, kad for-in atliks šią tvarką. (Išsami informacija šiame kitame atsakyme .)

Tačiau tai gali būti naudinga, ypač retų masyvų atveju , jei naudojate tinkamas atsargumo priemones:

 // '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]); } } 

Atkreipkite dėmesį į du patikrinimus:

  1. Kad objektas turi savo nuosavybę pagal šį pavadinimą (o ne tą, kurį jis paveldėjo iš savo prototipo), ir. \ T

  2. Kad raktas yra bazinė-10 skaitmeninė eilutė savo įprastoje eilutės formoje ir jos vertė yra <= 2 ^ 32 - 2 (tai yra 4 294 967 294). Iš kur kilęs šis skaičius? Tai yra masyvo indekso apibrėžties dalis specifikacijoje . Kiti numeriai (ne sveiki skaičiai, neigiami skaičiai, skaičiai didesni nei 2 ^ 32 - 2) nėra masyvo indeksai. 2 ^ 32 - 2 priežastis yra tai, kas daro didžiausią indekso reikšmę mažesnę nei 2 ^ 32 - 1 , o tai yra maksimali masyvo length vertė. (Pavyzdžiui, masyvo ilgis atitinka 32 bitų nepasirašytą sveikąjį skaičių.) (RobG patvirtinimas, kad komentare būtų nurodyta mano dienoraščio įraše, kad mano ankstesnis testas nebuvo visiškai teisingas).

Tai maža papildoma pridėtinė vertė kiekvienai kilpų iteracijai daugelyje matricų, bet jei turite retą masyvą, tai gali būti veiksmingesnis būdas kilti, nes tai tik fiksuojamų įrašų kilpos. Pvz., Aukščiau esančioje matricoje mes trunka tris kartus (už "0" , "10" ir "10000" - prisiminkite, kad tai yra eilutės), o ne 10 001 kartų.

Dabar nenorite ją rašyti kiekvieną kartą, todėl galite jį įdėti į savo įrankių rinkinį:

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

Ir tada mes jį naudosime taip:

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

Arba, jei jus domina tik testas „pakankamai geras daugeliu atvejų“, galite jį naudoti, tačiau tol, kol jis yra arti, tai ne visai teisinga:

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

4. Naudojimasis (naudokite netiesioginį iteratorių) (ES2015 +)

ES2015 į „JavaScript“ prideda iteratorių. Lengviausias būdas naudoti iteratorius yra naujas operatorius. Tai atrodo taip:

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

Išvada:

 a b c

Po viršeliais, kurie gauna iteratorių iš masyvo ir eina per jį, gauna iš jo vertybių. Jis neturi jokių problemų naudodamasis for-in , nes naudoja iteratorių, apibrėžtą objekto (masyvo), ir matricos nustato, kad jų iteratoriai pakartoja savo įrašus (o ne jų savybes). Skirtingai nei ES5 programoje, įrašų peržiūros tvarka yra jų indeksų eilės tvarka.

5. Naudokite iteratorių aiškiai (ES2015 +)

Kartais galite aiškiai naudoti iteratorių. Jūs taip pat galite tai padaryti, nors tai yra daug daugiau klouni nei for-of . Tai atrodo taip:

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

Iteratorius - tai objektas, atitinkantis Iterator apibrėžimą specifikacijoje. Jo next metodas grąžina naują rezultato objektą kiekvieną kartą, kai jį vadinate. Rezultato objektas turi nuosavybę, done , pasakoja, ar tai buvo padaryta, ir turto vertę su šios iteracijos verte. ( done neprivaloma, jei tai būtų false , value yra neprivaloma, jei ji nėra undefined ).

value skiriasi priklausomai nuo iteratoriaus; masyvai palaiko (bent jau) tris funkcijas, kurios grąžina iteratorius:

  • values() : Tai yra tas, kurį naudoju anksčiau. Ji grąžina iteratorių, kur kiekviena value yra šio iteracijos masyvo įrašas (aukščiau pateiktame pavyzdyje yra "a" , "b" ir "c" ).
  • keys() : grąžina iteratorių, kur kiekviena value yra šio iteracijos raktas (taigi, mūsų aukščiau, bus "0" , tada "1" , o tada "2" ).
  • entries() : grąžina iteratorių, kur kiekviena value yra masyvas [key, value] šiai iteracijai.

Tokiems objektams kaip masyvas

Be tikrosios masyvų, yra ir masyvo tipo objektų, kurių length nuosavybė ir savybės su skaitmeniniais pavadinimais: „ NodeList atvejai, arguments objektas ir kt. Kaip mes NodeList jų turinį?

Naudokite bet kurį iš aukščiau nurodytų parametrų masyvams.

Bent kai kurie, o gal ir dauguma ar net visi pirmiau minėti matricos dažnai naudojami vienodai gerai masyvo tipo objektams:

  1. Naudokite forEach ir susijusius (ES5 +)

    Įvairios „ Array.prototype “ funkcijos yra „sąmoningai bendro pobūdžio“ ir paprastai gali būti naudojamos objektams, pvz., Masyvui, naudojant Function#call . (Žr. Atsakomybės apribojimas dėl objektų, kuriuos priėmė priimančioji, šio atsakymo pabaigoje, tačiau tai yra reta problema.)

    Tarkime, kad norėjote naudoti forEachforEach Node forEach . Jūs tai padarytumėte:

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

    Jei ketinate tai padaryti daug, galbūt norėsite gauti funkcijų nuorodos kopiją kintamajame, kuris bus pakartotinai naudojamas, pavyzdžiui:

     // (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. Naudokite paprastą kilpą

    Akivaizdu, kad paprastas kilpas taikomas tokiems objektams kaip masyvas.

  3. Tinkamai naudokite for-in

    for-in su tokiomis pačiomis garantijomis, kaip ir masyvas, turėtų dirbti su objektais, panašiais į masyvą; Galima reikalauti rezervacijos, jei priimančioji šalis pateikia 1 punktą.

  4. Naudoti „ for-of (naudoti netiesioginį iteratorių) (ES2015 +)

    for-of naudos objekto pateiktą iteratorių (jei toks yra); turėsime pamatyti, kaip tai atsitinka su įvairiais panašiais į masyvo objektus, ypač su pagrindiniais failais. Pvz., querySelectorAllquerySelectorAll buvo atnaujinta, kad būtų palaikoma iteracija. „ HTMLCollection specifikacija nebuvo.

  5. Naudokite iteratorių aiškiai (ES2015 +)

    Žr. 4 numerį, mes turime pamatyti, kaip atsiskleidžia iteratoriai.

Sukurkite tikrą masyvą

Kitais atvejais objektą, pvz., Masyvą, galite konvertuoti į tikrą masyvą. Norėdami tai padaryti, stebėtinai lengva:

  1. Naudokite slice matavimo metodą

    Mes galime naudoti slice matricos metodą, kuris, kaip ir kiti pirmiau minėti metodai, yra „tyčia bendrinis“ ir todėl gali būti naudojamas su masyvo objektais, pavyzdžiui:

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

    Taigi, pavyzdžiui, jei norime konvertuoti „ NodeList į tikrą masyvą, galėtume tai padaryti:

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

    Žr. „Įspėjimas dėl priimančiųjų objektų“ toliau. Atkreipkite dėmesį, kad tai neveiks IE8 ir ankstesnėse versijose, o tai neleidžia naudoti tokių priimančiosios teikiamų objektų.

  2. Naudokite platinimo sintaksę ( ... )

    Taip pat galima naudoti ES2015 paskirstymo sintaksę su „JavaScript“ mechanizmais, kurie palaiko šią funkciją:

     var trueArray = [...iterableObject]; 

    Taigi, pavyzdžiui, jei norime konvertuoti „ NodeList į tikrą masyvą, su sklidimo sintaksė, jis tampa gana trumpas:

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

    Array.from (ES2015 +, bet lengvai užpildytas) sukuria masyvą iš objekto, pvz., Masyvo, jei reikia, pirmą kartą perduodant įrašus per atitikimo funkciją. Taigi:

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

    Arba, jei norite gauti žymių pavadinimų masyvą elementams, turintiems tam tikrą klasę, turite naudoti kartografavimo funkciją:

     // 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; }); 

Atkreipkite dėmesį į priimančiosios teikiamas paslaugas

Jei naudojate Array.prototype funkcijas su tokiais objektais kaip šeimininkai (DOM sąrašai ir kiti dalykai, kuriuos teikia naršyklė, o ne „JavaScript“ variklis), turite būti tikri, kad Array.prototype savo tikslinėje aplinkoje, kad įsitikintumėte, ar teikiamas objekto objektas veikia yra teisingas. Dauguma jų elgiasi teisingai (dabar), tačiau svarbu patikrinti. Taip yra todėl, kad dauguma „ Array.prototype metodų, kuriuos tikriausiai norite naudoti, remiasi priimančiosios pateiktu objektu, suteikdami sąžiningą atsakymą į abstrakčią [[HasProperty]] . Šio rašymo metu naršyklės atliko labai gerą darbą, tačiau 5.1 specifikacijoje teigiama, kad priimančiojo objektas gali būti ne teisingas. Tai yra §8.6.2 , kelios pastraipos po didele lentele šio skirsnio pradžioje, kur sakoma:

Priimantys objektai gali įgyvendinti šiuos vidinius metodus bet kokiu būdu, jei nenurodyta kitaip; Pavyzdžiui, viena galimybė yra ta, kad [[Get]] ir [[Put]] tam tikram prieglobos objektui iš tikrųjų [[HasProperty]] ir išsaugo turto vertes, tačiau [[HasProperty]] visada generuoja klaidingą .

(Negalėjau rasti ekvivalentiškos formuluotės ES2015 specifikacijoje, bet ji vis dar turi būti.) Vėlgi, kaip ir rašant bendrąjį prieglobos masyvo [[HasProperty]] šiuolaikinėse naršyklėse [pvz., „ [[HasProperty]] pavyzdžiai), [[HasProperty]] tvarkykite teisingą, bet svarbų patikrinti.)

6292
17 февр. Atsakymą pateikė TJ Crowder 17 vasaris. 2012-02-17 16:53 '12 at 4:53 pm 2012-02-17 16:53

Redaguoti : šis atsakymas beviltiškai pasenęs. Dėl modernesnio požiūrio ieškokite masyvo būdų . Susidomėjimo būdai gali būti:

  • už kiekvieną
  • kortelę
  • filtrą
  • užtrauktukas
  • sumažinti
  • kiekvienas
  • truputį

Standartinis būdas kartoti masyvą „ JavaScript“ yra for vanlo“:

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

Tačiau atkreipkite dėmesį, kad šis metodas yra geras tik tuo atveju, jei turite tankų matricą, o kiekvienas indeksas užima elementą. Jei masyvas yra nedidelis, tuomet su šiuo metodu galite susidurti su našumo problemomis, nes jūs eisite per daug indeksų, kurie iš tikrųjų nėra masyve. Tokiu atveju geriau naudoti. Tačiau turite naudoti tinkamas atsargumo priemones, kad užtikrintumėte, jog galioja tik reikalingos masyvo savybės (t. Y. Masyvo elementai), nes dėl „... for..in taip pat bus įtrauktos į senas naršykles arba jei papildomos savybės yra apibrėžtos kaip enumerable .

ECMAScript 5 programoje „ForEach“ bus naudojamas masyvo prototipas, tačiau jis nepalaikomas senesnėse naršyklėse. Todėl, kad galėtumėte ją naudoti nuosekliai, turite turėti ją palaikančią aplinką (pvz., „ Node.js “ serverio pusėje „JavaScript“) arba naudoti „Polyfill“. Tačiau šios funkcijos „Polyfill“ yra nereikšminga, ir todėl, kad kodą lengviau skaityti, ji turėtų būti įtraukta į „Polyfill“.

470
17 февр. PatrikAkerstrand atsakymas, pateiktas vasario 17 d. 2012-02-17 16:55 '12 at 4:55 pm 2012-02-17 16:55

Jei naudojate jQuery biblioteką, galite naudoti jQuery.each :

 var length = yourArray.length; for (var i = 0; i < length; i++) { // Do something with yourArray[i]. } 
214
17 февр. Atsakymas duotas Poonam 17 vasario mėn. 2012-02-17 17:01 '12, 17:01, 2012-02-17 17:01

Grįžkite atgal

Manau, kad ciklui atvirkščiai verta paminėti čia:

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

Privalumai:

  • Jums nereikia deklaruoti laikino kintamojo len arba lyginti jį su array.length kiekviename iteracijoje, o tai gali būti minutės optimizavimas.
  • Paprastai efektyvesnis yra brolių ir seserų pašalinimas iš DOM atvirkštine tvarka. (Naršyklė turi perkelti mažiau elementų į vidines matricas.)
  • Jei pakeisite masyvą ciklo metu, rodyklėje I arba po jo (pvz., Ištrinate ar įterpiate elementą į array[i] ), tiesioginė kilpa praleidžia elementą, kuris yra perkeliamas į kairę, kad padėtumėte i, arba iš naujo patikrina i-tą elementą, kuris buvo perkeltas į dešinę. Tradicinėje kilpoje galite atnaujinti „i“, kad nukreiptumėte į kitą elementą, kurį reikia apdoroti - 1, bet paprasčiausiai keisti iteracijos kryptį yra paprastesnis ir elegantiškesnis sprendimas .
  • Panašiai keičiant ar ištrinant įdėtus DOM elementus, atvirkštinis apdorojimas gali apeiti klaidas . Pavyzdžiui, prieš apdorodami savo vaikus, apsvarstykite galimybę pakeisti pagrindinio mazgo vidinįHTML. Kai pasiekiamas vaiko mazgas, jis bus atskirtas nuo DOM, pakeisdamas jį nauju palikuoniu, kai buvo parašytas pagrindinis internalHTML.
  • trumpesnis ir trumpesnis nei kai kurios kitos galimybės. Nors jis netenka forEach() ir forEach() for ... of .

Trūkumai:

  • Jis apdoroja elementus atvirkštine tvarka. Jei sukūrėte naują matricą iš rezultatų arba atspausdinote ekrane, išvestis, žinoma, bus atšaukta, palyginti su pradine tvarka.
  • Неоднократно вставляя братьев и сестер в DOM в качестве первого ребенка, чтобы сохранить их порядок, менее эффективен . (В браузере все равно придется перекладывать вещи.) Чтобы создавать узлы DOM эффективно и упорядоченно, просто переходите вперед и добавьте как обычно (а также используйте "фрагмент документа" ).
  • Обратный цикл запутывает для младших разработчиков. (Вы можете считать это преимущество, в зависимости от вашего прогноза.)

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