Domanda Per-su un array in JavaScript?


Come posso scorrere tutte le voci di un array usando JavaScript?

Ho pensato che fosse qualcosa del genere:

forEach(instance in theArray)

Dove theArray è il mio array, ma questo sembra essere errato.


3778
2018-02-17 13:51


origine


risposte:


TL; DR

  • Non usare for-in a meno che non lo si usi con le precauzioni o almeno si sappia perché potrebbe morderti.
  • Le tue migliori scommesse di solito sono

    • un for-of loop (solo ES2015 +),
    • Array#forEach (spec | MDN) (o dei suoi parenti some e tale) (solo ES5 +),
    • un semplice vecchio stile for ciclo continuo,
    • o for-in con le garanzie.

Ma c'è molte più da esplorare, continua a leggere ...


JavaScript ha una potente semantica per il looping attraverso array e oggetti tipo array. Ho diviso la risposta in due parti: Opzioni per array originali e opzioni per cose che sono semplicemente array-piace, come il arguments oggetto, altri oggetti iterabili (ES2015 +), raccolte DOM e così via.

Presto notare che è possibile utilizzare le opzioni ES2015 adesso, anche su motori ES5, di transpiling Da ES2015 a ES5. Cerca "ES2015 transpiling" / "ES6 transpiling" per altro ...

Ok, diamo un'occhiata alle nostre opzioni:

Per array effettivi

Hai tre opzioni in ECMAScript 5 ("ES5"), la versione più supportata al momento, e altre due aggiunte ECMAScript 2015 ("ES2015", "ES6"):

  1. Uso forEach e correlati (ES5 +)
  2. Usa un semplice for ciclo continuo
  3. Uso for-in  correttamente
  4. Uso for-of (utilizzare un iteratore implicitamente) (ES2015 +)
  5. Utilizzare un iteratore in modo esplicito (ES2015 +)

Dettagli:

1. Usa forEach e correlati

In qualsiasi ambiente vagamente moderno (quindi, non IE8) in cui si ha accesso a Array funzionalità aggiunte da ES5 (direttamente o utilizzando polifragioli), è possibile utilizzare forEach (spec | MDN):

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

forEach accetta una funzione di callback e, facoltativamente, un valore da utilizzare come this quando si chiama quella richiamata (non utilizzata sopra). Il callback viene chiamato per ogni voce dell'array, in ordine, saltando le voci inesistenti negli array sparsi. Anche se ho usato solo un argomento sopra, il callback è chiamato con tre: il valore di ogni voce, l'indice di quella voce e un riferimento alla matrice su cui stai iterando (nel caso in cui la tua funzione non lo abbia già a portata di mano ).

A meno che tu non stia supportando browser obsoleti come IE8 (che NetApps mostra con una quota di mercato appena superiore al 4% al momento in cui scrivo a settembre 2016), puoi usare tranquillamente forEach in una pagina Web di uso generale senza shim. Se hai bisogno di supportare browser obsoleti, shimming / polyfilling forEach è fatto facilmente (cerca "es5 shim" per diverse opzioni).

forEach ha il vantaggio che non è necessario dichiarare l'indicizzazione e le variabili di valore nell'ambito di contenimento, poiché vengono fornite come argomenti per la funzione di iterazione e sono quindi ottimizzate per tale iterazione.

Se sei preoccupato per il costo di esecuzione di effettuare una chiamata di funzione per ogni voce di array, non essere; dettagli.

Inoltre, forEach è la funzione "loop through them all", ma ES5 ha definito diverse altre utili funzioni "fai il tuo lavoro attraverso l'array e fai le cose", tra cui:

  • every (interrompe il ciclo la prima volta che la richiamata ritorna false o qualcosa di falso)
  • some (interrompe il ciclo la prima volta che la richiamata ritorna true o qualcosa di vero)
  • filter (crea una nuova matrice che include elementi in cui la funzione di filtro ritorna true e omettendo quelli in cui ritorna false)
  • map (crea una nuova matrice dai valori restituiti dal callback)
  • reduce (crea un valore chiamando ripetutamente il callback, passando i valori precedenti, vedi le specifiche per i dettagli, utile per sommare il contenuto di un array e molte altre cose)
  • reduceRight (piace reduce, ma funziona in ordine discendente anziché ascendente)

2. Usa un semplice for ciclo continuo

A volte i vecchi modi sono i migliori:

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

Se la lunghezza dell'array non cambia durante il ciclo, ed è in un codice sensibile alle prestazioni (improbabile), una versione leggermente più complicata che afferra la lunghezza in primo piano potrebbe essere un minuscolo un po 'più veloce:

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

E / o contando indietro:

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

Ma con i moderni motori JavaScript, è raro che tu debba eliminare quell'ultimo pezzetto di succo.

In ES2015 e versioni successive, è possibile rendere le proprie variabili di indice e valore locali for ciclo continuo:

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"

E quando lo fai, non solo value ma anche index viene ricreato per ogni iterazione del ciclo, il che significa che le chiusure create nel corpo del loop mantengono un riferimento al index (e value) creato per quella specifica iterazione:

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

Se avevi cinque div, riceverai "Index is: 0" se hai fatto clic sul primo e "Index is: 4" se hai fatto clic sull'ultimo. Questo fa non lavoro se usi var invece di let.

3. Uso for-in  correttamente

Avrai gente che ti dirà di usarla for-in, ma non è quello che for-in è per. for-in scorre attraverso il proprietà enumerabili di un oggetto, non gli indici di una matrice. L'ordine non è garantito, nemmeno in ES2015 (ES6). ES2015 definisce un ordine per le proprietà oggetto (via [[OwnPropertyKeys]], [[Enumerate]]e le cose che li usano come Object.getOwnPropertyKeys), ma ciò non definirlo for-in seguirà quell'ordine (Dettagli in questa altra risposta.)

Comunque può essere utile, in particolare per scarso array, se usi le protezioni appropriate:

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

Nota i due controlli:

  1. Che l'oggetto ha il suo proprio proprietà con quel nome (non una che eredita dal suo prototipo), e

  2. Che la chiave sia una stringa numerica base 10 nella sua normale forma di stringa e il suo valore è <= 2 ^ 32 - 2 (che è 4.294.967.294). Da dove viene quel numero? Fa parte della definizione di un indice di array nella specifica. Altri numeri (non interi, numeri negativi, numeri maggiori di 2 ^ 32 - 2) non sono indici di array. La ragione è 2 ^ 32 - 2 è quello che rende il più grande valore di indice inferiore a 2 ^ 32 - 1, che è il valore massimo di un array length possono avere. (Ad esempio, la lunghezza di una matrice si adatta a un intero senza segno a 32 bit.) (Puntelli su RobG per indicare un commento sul mio post del blog che il mio test precedente non era del tutto corretto).

Questo è un po 'di overhead aggiunto per iterazione del ciclo sulla maggior parte degli array, ma se si dispone di un scarso array, può essere un modo più efficiente di eseguire il ciclo perché si limita solo alle voci effettivamente esistenti. Ad esempio, per la matrice sopra, facciamo un ciclo totale di tre volte (per le chiavi "0", "10", e "10000"- ricorda, sono stringhe), non 10,001 volte.

Ora, non vorrai scriverlo ogni volta, quindi potresti metterlo nel tuo toolkit:

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

E poi lo useremmo in questo modo:

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

Oppure, se ti interessa solo un test "abbastanza buono per la maggior parte dei casi", puoi usare questo, ma mentre è vicino, non è del tutto corretto:

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

4. Usa for-of (utilizzare un iteratore implicitamente) (ES2015 +)

ES2015 aggiunge iteratori in JavaScript. Il modo più semplice per usare gli iteratori è il nuovo for-of dichiarazione. Sembra questo:

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

Produzione:

un
B
c

Sotto le coperte, quello ottiene un iteratore dalla matrice e scorre attraverso di essa, ottenendo i valori da essa. Questo non ha il problema che l'utilizzo for-in ha, perché usa un iteratore definito dall'oggetto (l'array), e gli array definiscono che i loro iteratori iterano attraverso i loro inserimenti (non le loro proprietà). a differenza di for-in in ES5, l'ordine in cui le voci sono visitate è l'ordine numerico dei loro indici.

5. Utilizzare un iteratore in modo esplicito (ES2015 +)

A volte, potresti voler usare un iteratore espressamente. Puoi farlo anche tu, anche se è molto più clunkier di for-of. Sembra questo:

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

L'iteratore è un oggetto che corrisponde alla definizione di Iterator nella specifica. Suo next il metodo restituisce un nuovo risultato oggetto ogni volta che lo chiami. L'oggetto risultato ha una proprietà, done, dicendoci se è stato fatto, e una proprietà value con il valore per tale iterazione. (done è facoltativo se lo fosse false, value è facoltativo se lo fosse undefined.)

Il significato di value varia a seconda dell'iteratore; gli array supportano (almeno) tre funzioni che restituiscono gli iteratori:

  • values(): Questo è quello che ho usato sopra. Restituisce un iteratore in cui ciascuno value è la voce dell'array per quell'iterazione ("a", "b", e "c" nell'esempio precedente).
  • keys(): Restituisce un iteratore in cui ciascuno value è la chiave per quell'iterazione (quindi per il nostro a sopra, sarebbe "0", poi "1", poi "2").
  • entries(): Restituisce un iteratore in cui ciascuno value è un array nel modulo [key, value] per quella iterazione.

Per oggetti tipo array

A parte i veri array, ci sono anche matrice simile oggetti che hanno a length proprietà e proprietà con nomi numerici: NodeList istanze, il arguments oggetto, ecc. Come facciamo a scorrere i loro contenuti?

Utilizzare una delle opzioni sopra per gli array

Almeno alcuni, e forse la maggior parte o anche tutti gli approcci dell'array sopra si applicano spesso anche a oggetti di tipo array:

  1. Uso forEach e correlati (ES5 +)

    Le varie funzioni su Array.prototype sono "intenzionalmente generici" e di solito possono essere utilizzati su oggetti di tipo array attraverso Function#call o Function#apply. (Vedi il Avvertenza per oggetti forniti dall'host alla fine di questa risposta, ma è un problema raro.)

    Supponiamo che tu volessi usare forEach a Node'S childNodes proprietà. Faresti questo:

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

    Se lo farai molto, ti consigliamo di prendere una copia del riferimento alla funzione in una variabile per il riutilizzo, ad esempio:

    // (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. Usa un semplice for ciclo continuo

    Ovviamente, un semplice for il ciclo si applica agli oggetti tipo array.

  3. Uso for-in  correttamente

    for-in con le stesse misure di sicurezza di un array dovrebbe funzionare anche con oggetti di tipo array; l'avvertenza per gli oggetti forniti dall'host sopra il numero 1 può essere applicata.

  4. Uso for-of (utilizzare un iteratore implicitamente) (ES2015 +)

    for-of utilizzerà l'iteratore fornito dall'oggetto (se presente); dovremo vedere come questo gioca con i vari oggetti tipo array, in particolare quelli forniti dall'host. Ad esempio, la specifica per il NodeList a partire dal querySelectorAll è stato aggiornato per supportare l'iterazione. Le specifiche per il HTMLCollection a partire dal getElementsByTagName non era.

  5. Utilizzare un iteratore in modo esplicito (ES2015 +)

    Vedi # 4, dovremo vedere come si svolgono gli iteratori.

Crea un vero array

Altre volte, potresti voler convertire un oggetto simile ad un array in un vero array. Fare ciò è sorprendentemente facile:

  1. Usa il slice metodo degli array

    Possiamo usare il slice metodo degli array, che come gli altri metodi sopra menzionati è "intenzionalmente generico" e quindi può essere usato con oggetti tipo array, come questo:

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

    Quindi, per esempio, se vogliamo convertire un NodeList in un vero array, potremmo fare questo:

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

    Vedere il Avvertenza per oggetti forniti dall'host sotto. In particolare, si noti che ciò non riuscirà in IE8 e versioni precedenti, che non consentono di utilizzare oggetti forniti dall'host come this come quello.

  2. Uso diffusione della sintassi (...)

    È anche possibile usare ES2015's diffusione della sintassi con motori JavaScript che supportano questa funzionalità:

    var trueArray = [...iterableObject];
    

    Quindi, per esempio, se vogliamo convertire un NodeList in un vero array, con la sintassi di diffusione questo diventa abbastanza succinto:

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

    Array.from (ES2015 +, ma facilmente polyfilled) crea una matrice da un oggetto simile ad un array, opzionalmente passando prima le voci attraverso una funzione di mappatura. Così:

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

    O se volessi ottenere una matrice dei nomi dei tag degli elementi con una data classe, dovresti usare la funzione di mappatura:

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

Avvertenza per oggetti forniti dall'host

Se usi Array.prototype funzioni con host-disponibile oggetti tipo array (liste DOM e altre cose fornite dal browser piuttosto che dal motore JavaScript), è necessario essere sicuri di testare negli ambienti di destinazione per assicurarsi che l'oggetto fornito dall'host si comporti correttamente. La maggior parte si comporta correttamente (ora), ma è importante testare. Il motivo è che la maggior parte del Array.prototype i metodi che probabilmente vorrai utilizzare si basano sull'oggetto fornito dall'host che fornisce una risposta onesta all'astratto [[HasProperty]] operazione. Al momento della stesura di questo documento, i browser fanno un ottimo lavoro, ma le specifiche 5.1 hanno consentito la possibilità che un oggetto fornito dall'host non sia onesto. È dentro §8.6.2, diversi paragrafi sotto il grande tavolo vicino all'inizio di quella sezione), dove si dice:

Gli oggetti host possono implementare questi metodi interni in qualsiasi modo se non diversamente specificato; per esempio, una possibilità è questa [[Get]] e [[Put]] per un particolare oggetto host, infatti, recupera e memorizza valori di proprietà ma [[HasProperty]] genera sempre falso.

(Non sono riuscito a trovare la verbiage equivalente nelle specifiche ES2015, ma è ancora possibile che sia ancora così.) Di nuovo, al momento della stesura degli oggetti comuni simili a host forniti da host nei moderni browser [NodeList istanze, per esempio] fare maniglia [[HasProperty]] correttamente, ma è importante testare).


5974
2018-02-17 13:53



modificare: Questa risposta è irrimediabilmente obsoleta. Per un approccio più moderno, guarda i metodi disponibili su un array. I metodi di interesse potrebbero essere:

  • per ciascuno
  • carta geografica
  • filtro
  • cerniera lampo
  • ridurre
  • ogni
  • alcuni

Il modo standard per iterare un array in JavaScript è una vaniglia for-ciclo continuo:

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

Si noti, tuttavia, che questo approccio è valido solo se si dispone di un array denso e ogni indice è occupato da un elemento. Se la matrice è sparsa, allora si può incorrere in problemi di prestazioni con questo approccio, dal momento che si itererà su molti indici che non veramente esistono nell'array. In questo caso, a for .. in-loop potrebbe essere un'idea migliore. però, è necessario utilizzare le protezioni appropriate per garantire che solo le proprietà desiderate dell'array (ovvero gli elementi dell'array) vengano applicate, dal momento che for..in-loop verrà enumerato anche nei browser legacy o se le proprietà aggiuntive sono definite come enumerable.

In ECMAScript 5 ci sarà un metodo forEach sul prototipo dell'array, ma non è supportato nei browser legacy. Quindi, per poterlo utilizzare in modo coerente, è necessario disporre di un ambiente che lo supporti (ad esempio, Node.js per lato server JavaScript), o utilizzare un "Polyfill". Il Polyfill per questa funzionalità è, tuttavia, banale e poiché rende il codice più facile da leggere, è un buon polyfill da includere.


451
2018-02-17 13:55



Se stai usando il jQuery libreria, puoi usare jQuery.each:

$.each(yourArray, function(index, value) {
  // do your stuff here
});

MODIFICARE : 

Come da domanda, l'utente desidera il codice in javascript al posto di jquery, quindi la modifica è

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

205
2018-02-17 14:01



Loop indietro

Penso che la inverso per loop merita una menzione qui:

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

vantaggi:

  • Non è necessario dichiarare un temporaneo len variabile, o confrontare contro array.length su ogni iterazione, ognuna delle quali potrebbe essere un minuto di ottimizzazione.
  • Rimozione di fratelli di solito è il DOM in ordine inverso più efficiente. (Il browser deve fare meno spostamento degli elementi nei suoi array interni).
  • Se tu modificare la matrice durante il ciclo, all'indice o dopo l'indice io (ad esempio, rimuovi o inserisci un elemento in array[i]), quindi un ciclo in avanti salta l'oggetto spostato a sinistra in posizione ioo rielaborare il iol'oggetto che è stato spostato a destra. In un ciclo tradizionale, tu poteva aggiornare io per puntare al prossimo elemento che ha bisogno di elaborazione - 1, ma semplicemente invertendo la direzione dell'iterazione è spesso un più semplice e soluzione più elegante.
  • Allo stesso modo, quando si modifica o si rimuove nidificato Elementi DOM, elaborazione in senso inverso aggirare gli errori. Ad esempio, prendere in considerazione la possibilità di modificare l'innerHTML di un nodo genitore prima di gestirne i figli. Quando viene raggiunto il nodo figlio, verrà staccato dal DOM, dopo essere stato sostituito da un figlio appena creato quando è stato scritto il innerHTML del genitore.
  • È più breve digitare, e leggere, rispetto ad alcune delle altre opzioni disponibili. Anche se perde forEach() e agli ES6 for ... of.

svantaggi:

  • Elabora gli articoli in ordine inverso. Se stavi creando una nuova matrice dai risultati o stampando le cose sullo schermo, naturalmente l'uscita sarà invertita rispetto all'ordine originale.
  • L'inserimento ripetuto di fratelli nel DOM come primo figlio per mantenere il loro ordine è meno efficiente. (Il browser continuerebbe a dover spostare le cose a posto.) Per creare nodi DOM in modo efficiente e in ordine, basta eseguire il ciclo avanti e aggiungere come di consueto (e utilizzare anche un "frammento di documento").
  • Il ciclo inverso è confusione agli sviluppatori junior. (Puoi considerare che un vantaggio, a seconda della tua prospettiva.)

Dovrei sempre usarlo?

Alcuni sviluppatori usano il ciclo inverso per per impostazione predefinita, a meno che non vi sia una buona ragione per andare avanti.

Sebbene i guadagni in termini di prestazioni siano in genere insignificanti, è una specie di urla:

"Basta fare questo per ogni elemento della lista, non mi interessa per l'ordine!"

Comunque in pratica è così non in realtà una indicazione affidabile di intento, dal momento che è indistinguibile da quelle occasioni in cui tu fare preoccuparsi per l'ordine, e davvero fare bisogno per girare in senso inverso. Quindi, in realtà, sarebbe necessario un altro costrutto per esprimere con precisione l'intento "non interessa", qualcosa che al momento non è disponibile nella maggior parte delle lingue, incluso ECMAScript, ma che potrebbe essere chiamato, ad esempio, forEachUnordered().

Se l'ordine non ha importanza, e efficienza è una preoccupazione (nel ciclo più interno di un motore di gioco o di animazione), quindi può essere accettabile utilizzare il ciclo inverso come schema di partenza. Basta ricordare che vedendo un inverso per il ciclo nel codice esistente non significa necessariamente che l'ordine è irrilevante!

È meglio usare forEach ()

In generale per codice di livello superiore dove chiarezza e sicurezza sono maggiori preoccupazioni, vorrei raccomandare l'utilizzo Array::forEach come modello predefinito:

  • È chiaro da leggere.
  • Indica quello io non verrà spostato all'interno del blocco (che è sempre una possibile sorpresa che si nasconde a lungo for e while loop).
  • Ti dà una portata gratuita per chiusure.
  • Riduce la perdita di variabili locali e la collisione accidentale con (e la mutazione di) variabili esterne.

Quindi, quando vedi il ciclo inverso per il codice, è un suggerimento che è invertito per una buona ragione (forse uno dei motivi sopra descritti). E vedere un tradizionale "forward loop" può indicare che lo spostamento può aver luogo.

(Se la discussione sull'intento non ha senso per te, allora tu e il tuo codice potreste trarre beneficio dall'osservare la lezione di Crockford Stile di programmazione e il tuo cervello.)


Come funziona?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

Lo noterai i-- è la clausola media (dove di solito vediamo un confronto) e l'ultima clausola è vuota (dove di solito vediamo i++). Ciò significa che i-- è anche usato come il condizione per la continuazione. Fondamentalmente, viene eseguito e controllato prima ogni iterazione.

  • Come può iniziare array.length senza esplodere?

    Perché i-- piste prima ogni iterazione, alla prima iterazione in realtà accediamo all'elemento in array.length - 1 che evita qualsiasi problema con Array-out-of-limiti  undefined elementi.

  • Perché non smette di iterare prima dell'indice 0?

    Il ciclo interromperà l'iterazione quando la condizione i-- valuta ad un valore di falso (quando produce 0).

    Il trucco è che a differenza --i, il finale i-- decrementi dell'operatore i ma produce il valore prima il decremento. La tua console può dimostrarlo:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    Quindi sull'ultima versione, io era precedentemente 1 e il i-- l'espressione lo cambia 0 ma in realtà cede 1 (veritiero), e così la condizione passa. Alla prossima iterazione i-- i cambiamenti io a -1 ma produce 0 (falso), causando l'interruzione immediata della fine del ciclo.

    Nei tradizionali forward per loop, i++ e ++i sono intercambiabili (come fa notare Douglas Crockford). Tuttavia nel verso inverso, perché il nostro decremento è anche la nostra espressione condizionale, dobbiamo restare fedeli i-- se vogliamo elaborare l'articolo all'indice 0.


banalità

Ad alcune persone piace disegnare una piccola freccia sul retro for loop e termina con un occhiolino:

for (var i = array.length; i --> 0 ;) {

I crediti vanno alla WYL per avermi mostrato i vantaggi e gli orrori del ciclo inverso.


88
2018-05-02 14:21



Alcuni Cuso delle lingue in stile foreach per scorrere le enumerazioni. In JavaScript questo è fatto con il for..in struttura del ciclo:

var index,
    value;
for (index in obj) {
    value = obj[index];
}

C'è un problema. for..in passerà in rassegna tutti i membri enumerabili dell'oggetto e i membri sul suo prototipo. Per evitare di leggere valori ereditati attraverso il prototipo dell'oggetto, è sufficiente verificare se la proprietà appartiene all'oggetto:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

Inoltre, ECMAScript 5 ha aggiunto un forEach metodo a Array.prototypeche può essere usato per enumerare su un array usando un calback (il polyfill è presente nei documenti, quindi puoi ancora usarlo per i browser più vecchi):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

È importante notare questo Array.prototype.forEach non si interrompe quando il callback ritorna false. jQuery e Underscore.js fornire le proprie variazioni su each per fornire anelli che possono essere cortocircuitati.


70
2018-02-17 14:00



Se si desidera eseguire il loop su un array, utilizzare la tre parti standard for ciclo continuo.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

È possibile ottenere alcune ottimizzazioni delle prestazioni tramite la memorizzazione nella cache myArray.length o iterando su di esso all'indietro.


30
2018-02-17 13:55



UN per ciascuno implementazione (vedi in jsFiddle):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);

25
2018-04-10 00:26



Se non ti dispiace svuotare l'array:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x conterrà l'ultimo valore di y e sarà rimosso dall'array. Puoi anche usare shift() che darà e rimuoverà il primo oggetto da y.


25
2018-03-10 02:37



So che questo è un vecchio post e ci sono già tante grandi risposte. Per un po 'più di completezza ho pensato di buttarne un'altra usando AngularJS. Ovviamente, questo si applica solo se stai usando Angular, ovviamente, comunque mi piacerebbe metterlo lo stesso.

angular.forEach prende 2 argomenti e un terzo argomento opzionale. Il primo argomento è l'oggetto (array) per iterare sopra, il secondo argomento è la funzione iteratore, e il terzo argomento opzionale è il contesto dell'oggetto (fondamentalmente riferito all'interno del ciclo come 'questo'.

Esistono diversi modi per utilizzare il ciclo forEach di angular. Il più semplice e probabilmente il più usato è

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Un altro modo è utile per copiare elementi da una matrice all'altra

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

Tuttavia, non devi farlo, puoi semplicemente fare quanto segue ed è equivalente all'esempio precedente:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

Ora ci sono pro e contro dell'uso del angular.forEach funzione al contrario del sapore di vaniglia integrato for ciclo continuo.

Professionisti

  • Facile leggibilità
  • Facile scrivibilità
  • Se disponibile, angular.forEach utilizzerà il ciclo ESE forEach. Ora, arriverò all'efficienza nella sezione contro, come lo sono i cicli forEach tanto più lento dei cicli for. Lo dico come professionista perché è bello essere coerenti e standardizzati.

Considera i seguenti 2 cicli annidati, che fanno esattamente la stessa cosa. Diciamo che abbiamo 2 matrici di oggetti e ogni oggetto contiene una serie di risultati, ognuno dei quali ha una proprietà Value che è una stringa (o qualsiasi altra cosa). E diciamo che abbiamo bisogno di scorrere su ciascuno dei risultati e se sono uguali, allora esegui qualche azione:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

Certo, questo è un esempio ipotetico molto semplice, ma ho scritto triple embedded per loop usando il secondo approccio e lo è stato molto difficile da leggere e scrivere per quella materia.

Contro

  • Efficienza. angular.forEache il nativo forEach, del resto, sono entrambi così tanto più lento del normale for loop .... su 90% più lento. Pertanto, per i set di dati di grandi dimensioni, è meglio attenersi al nativo for ciclo continuo.
  • Nessuna interruzione, continuazione o restituzione del supporto. continue è attualmente supportato da "incidente", per continuare in un angular.forEach metti semplice a return; affermazione nella funzione come angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); che lo farà continuare fuori dalla funzione per quella iterazione. Questo è anche dovuto al fatto che il nativo forEach non supporta né rompere né continuare.

Sono sicuro che ci sono anche altri pro e contro, e per favore sentiti libero di aggiungere qualsiasi cosa tu ritenga opportuno. Sento che, in fondo, se hai bisogno di efficienza, segui solo il nativo for loop per le tue esigenze di loop. Ma, se i set di dati sono più piccoli e un po 'di efficienza è ok a rinunciare in cambio di leggibilità e scrivibilità, quindi con tutti i mezzi gettare un angular.forEach in quel ragazzaccio.


25
2018-06-20 22:56



Una soluzione facile ora sarebbe quella di utilizzare il libreria underscore.js. Fornisce molti strumenti utili, come ad esempio each e delegherà automaticamente il lavoro al nativo forEach se disponibile.

Un esempio di CodePen di come funziona è:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

Guarda anche


24
2017-07-17 09:07