Per ciascuno su un array in JavaScript


4684

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

Ho pensato che fosse qualcosa del genere:

forEach(instance in theArray)

Dov'è il theArraymio array, ma questo sembra essere errato.


16
L'ho cercato, ma l'ho cercato forEach e non solo for. come detto, in c # era un po 'diverso, e questo mi ha confuso :)
Dante1986,

6
ECMAScript & nbsp; 6 conterrà forse il costrutto "for ... of". Vedere per ... di (MDN) per ulteriori informazioni. Puoi già provarlo con le versioni recenti di Firefox.
Slaven Rezic,

36
Array.ForEach è circa il 95% più lento di for () in per ciascuno per gli array in JavaScript. Vedere questo test delle prestazioni online: jsperf.com/fast-array-foreach via coderwall.com/p/kvzbpa
molokoloco

77
Per molte situazioni che il 95% più lento non sarà significativo blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html
David Sykes

7
Al contrario, in Python è più efficiente usare le funzioni piuttosto che usare i loop tradizionali. (Consideralo i < lene i++può essere fatto dal motore, piuttosto che dall'interprete.)
joeytwiddle

Risposte:


7022

TL; DR

  • Non utilizzarlo a for-inmeno che non lo si usi con protezioni o almeno non si sia consapevoli del motivo per cui potrebbe morderti.
  • Le tue migliori scommesse sono di solito

    • un for-ofloop (solo ES2015 +),
    • Array#forEach( spec| MDN) (o suoi parenti somee simili) (solo ES5 +),
    • un semplice forciclo vecchio stile ,
    • o for-incon garanzie.

Ma c'è molto altro da esplorare, continua a leggere ...


JavaScript ha una potente semantica per il looping di matrici e oggetti simili a array. Ho diviso la risposta in due parti: opzioni per array autentici e opzioni per elementi che sono solo simili a array , come l' argumentsoggetto, altri oggetti iterabili (ES2015 +), raccolte DOM e così via.

Presto noterò che ora puoi usare le opzioni ES2015 , anche sui motori ES5, trasferendo ES2015 in ES5. Cerca "ES2015 transpiling" / "ES6 transpiling" per ulteriori informazioni ...

Ok, diamo un'occhiata alle nostre opzioni:

Per array effettivi

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

  1. Utilizzo forEache relativi (ES5 +)
  2. Usa un semplice forciclo
  3. Utilizzare for-in correttamente
  4. Usa for-of(usa implicitamente un iteratore) (ES2015 +)
  5. Utilizzare esplicitamente un iteratore (ES2015 +)

Dettagli:

1. Uso forEache relativi

In qualsiasi ambiente vagamente moderno (quindi, non IE8) in cui hai accesso alle Arrayfunzionalità aggiunte da ES5 (direttamente o usando i polyfill), puoi usare forEach( spec| MDN):

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

forEachaccetta una funzione di callback e, facoltativamente, un valore da usare come thisquando si chiama quel callback (non usato 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 all'array su cui stai ripetendo (nel caso in cui la tua funzione non lo abbia già a portata di mano ).

A meno che tu non supporti browser obsoleti come IE8 (che NetApps mostra con una quota di mercato di poco superiore al 4% al momento della stesura di questo scritto a settembre 2016), puoi tranquillamente utilizzarli forEachin una pagina web per uso generico senza uno spessore. Se è necessario supportare browser obsoleti, lo shimming / polyfilling forEachè facilmente eseguibile (cercare "shim es5" per diverse opzioni).

forEach ha il vantaggio di non dover dichiarare le variabili di indicizzazione e di valore nell'ambito di contenimento, poiché vengono fornite come argomenti alla funzione di iterazione e sono così ben mirate a tale iterazione.

Se sei preoccupato per il costo di runtime di effettuare una chiamata di funzione per ogni voce dell'array, non esserlo; dettagli .

Inoltre, forEachè la funzione "loop through them all", ma ES5 ha definito diverse altre utili funzioni "work through the array and do things", tra cui:

  • every(interrompe il looping la prima volta che il callback ritorna falseo qualcosa di falso)
  • some(interrompe il looping la prima volta che il callback ritorna trueo qualcosa di vero)
  • filter(crea un nuovo array includendo elementi in cui la funzione filtro ritorna truee omette quelli in cui ritorna false)
  • map (crea un nuovo array dai valori restituiti dal callback)
  • reduce (crea un valore chiamando ripetutamente il callback, passando i valori precedenti; vedere le specifiche per i dettagli; utile per sommare il contenuto di un array e molte altre cose)
  • reduceRight(come reduce, ma funziona in ordine decrescente anziché crescente)

2. Utilizzare un semplice forciclo

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 della matrice non cambierà durante il ciclo, ed è nel codice prestazioni sensibili (improbabile), una versione un po 'più complicato afferrare la lunghezza in attacco potrebbe essere un piccolo 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 all'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 abbia bisogno di eliminare quell'ultimo po 'di succo.

In ES2015 e versioni successive, è possibile rendere le variabili dell'indice e del valore locali nel forloop:

let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
    console.log(index, value);
}
//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 valuema indexviene anche ricreato per ogni iterazione di loop, il che significa che le chiusure create nel corpo del loop mantengono un riferimento a index(e value) creato per quella iterazione specifica:

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

Se avessi cinque div, otterrai "Indice è: 0" se fai clic sul primo e "Indice è: 4" se fai clic sull'ultimo. Questo non funziona se si utilizza varinvece di let.

3. Utilizzare for-in correttamente

Avrai gente che ti dice di usare for-in, ma non for-inè per questo . for-inscorre attraverso le proprietà enumerabili di un oggetto , non gli indici di un array. L'ordine non è garantito , nemmeno in ES2015 (ES6). ES2015 + definisce un ordine per obiettare le proprietà (tramite [[OwnPropertyKeys]], [[Enumerate]]e cose che le usano come Object.getOwnPropertyKeys), ma non ha definito che for-inseguirebbe quell'ordine; ES2020 invece lo ha fatto. (Dettagli in questa altra risposta .)

Gli unici casi d'uso reali per for-insu un array sono:

  • E 'un sparse array con enormi lacune in essa, o
  • Stai usando proprietà non elementali e vuoi includerle nel loop

Guardando solo quel primo esempio: puoi usare for-inper visitare quegli elementi di array sparsi 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 checks are
        /^0$|^[1-9]\d*$/.test(key) &&    // explained
        key <= 4294967294                // below
        ) {
        console.log(a[key]);
    }
}

Nota i tre controlli:

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

  2. Che la chiave è costituita da tutte le cifre decimali (ad es. Forma di stringa normale, non notazione scientifica) e

  3. Che il valore della chiave quando viene forzato su un numero è <= 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. Il motivo per cui è 2 ^ 32 - 2 è che rende il valore dell'indice più grande uno inferiore a 2 ^ 32 - 1 , che è il valore massimo che lengthpuò avere un array . (Ad esempio, la lunghezza di un array si adatta a un numero intero senza segno a 32 bit.) (Propone a RobG per aver sottolineato in un commento sul mio post sul blog che il mio test precedente non era corretto.)

Non lo faresti nel codice in linea, ovviamente. Scriveresti una funzione di utilità. Forse:

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

ES2015 ha aggiunto iteratori a JavaScript. Il modo più semplice per usare gli iteratori è la nuova for-ofaffermazione. Sembra così:

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

Sotto le copertine, ottiene un iteratore dall'array e lo attraversa, ottenendo i valori da esso. Questo non ha il problema che l'utilizzo for-inha, perché usa un iteratore definito dall'oggetto (l'array) e gli array definiscono che i loro iteratori iterano attraverso le loro voci (non le loro proprietà). A differenza for-indi ES5, l'ordine in cui le voci vengono visitate è l'ordine numerico dei loro indici.

5. Utilizzare esplicitamente un iteratore (ES2015 +)

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

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

L'iteratore è un oggetto che corrisponde alla definizione Iteratore nelle specifiche. Il suo nextmetodo restituisce un nuovo oggetto risultato ogni volta che lo chiami. L'oggetto risultato ha una proprietà doneche ci dice se è stato fatto e una proprietà valuecon il valore per quell'iterazione. ( doneè facoltativo se lo fosse false, valueè facoltativo se lo fosse undefined.)

Il significato di valuevaria a seconda dell'iteratore; le matrici supportano (almeno) tre funzioni che restituiscono iteratori:

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

Per oggetti simili a array

Oltre alle vere matrici, ci sono anche oggetti simili a array che hanno una lengthproprietà e proprietà con nomi numerici: NodeLististanze, l' argumentsoggetto, ecc. Come possiamo scorrere il loro contenuto?

Utilizzare una delle opzioni sopra per gli array

Almeno alcuni, e forse la maggior parte o anche tutti, degli approcci di array sopra spesso si applicano ugualmente bene ad oggetti simili a array:

  1. Utilizzo forEache relativi (ES5 +)

    Le varie funzioni Array.prototypesono "intenzionalmente generiche" e di solito possono essere utilizzate su oggetti simili a array tramite Function#callo Function#apply. (Vedi gli avvertimenti per gli oggetti forniti dall'host alla fine di questa risposta, ma è un problema raro.)

    Si supponga di voler utilizzare forEachsu una Node's childNodesproprietà. Faresti questo:

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

    Se hai intenzione di farlo molto, potresti prendere una copia del riferimento della funzione in una variabile per riutilizzarla, 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 forciclo

    Ovviamente, un semplice forciclo si applica agli oggetti simili a array.

  3. Utilizzare for-in correttamente

    for-incon le stesse garanzie di un array dovrebbe funzionare anche con oggetti simili a array; può essere applicato il avvertimento per gli oggetti forniti dall'host sul n. 1 sopra.

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

    for-ofutilizza l' iteratore fornito dall'oggetto (se presente). Ciò include oggetti forniti dall'host. Ad esempio, le specifiche per il NodeListda sono querySelectorAllstate aggiornate per supportare l'iterazione. Le specifiche per il HTMLCollectionda getElementsByTagNamenon lo erano.

  5. Utilizzare esplicitamente un iteratore (ES2015 +)

    Vedi # 4.

Crea un array vero

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

  1. Usa il slicemetodo degli array

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

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

    Quindi, ad esempio, se vogliamo convertire un NodeListin un vero array, potremmo farlo:

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

    Vedi le avvertenze per gli oggetti forniti dall'host di seguito. In particolare, si noti che ciò non funzionerà in IE8 e precedenti, il che non consente di utilizzare oggetti forniti dall'host in thisquesto modo.

  2. Usa sintassi diffusa ( ...)

    È anche possibile utilizzare la sintassi diffusa di ES2015 con motori JavaScript che supportano questa funzione. Ad esempio for-of, utilizza l' iteratore fornito dall'oggetto (vedere # 4 nella sezione precedente):

    var trueArray = [...iterableObject];

    Quindi, per esempio, se vogliamo convertire un NodeListin un vero array, con la sintassi diffusa questo diventa abbastanza sintetico:

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

    Array.from (spec) | (MDN) (ES2015 +, ma facilmente polifilabile) crea un array da un oggetto simile a un array, opzionalmente passando prima le voci attraverso una funzione di mappatura. Così:

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

    Oppure, se desideri ottenere una matrice dei nomi dei tag degli elementi con una determinata classe, dovresti utilizzare 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 si utilizzano Array.prototypefunzioni con oggetti simili a array forniti dall'host (elenchi DOM e altri elementi forniti dal browser anziché dal motore JavaScript), è necessario assicurarsi 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 testarlo. Il motivo è che la maggior parte dei Array.prototypemetodi che probabilmente vorrai utilizzare si basano sull'oggetto fornito dall'host che fornisce una risposta onesta [[HasProperty]]all'operazione astratta . Al momento della stesura di questo documento, i browser fanno un ottimo lavoro, ma la specifica 5.1 ha consentito la possibilità che un oggetto fornito dall'host non sia onesto. È in §8.6.2 , diversi paragrafi sotto il grande tavolo vicino all'inizio di quella sezione), dove dice:

Gli oggetti host possono implementare questi metodi interni in qualsiasi modo se non diversamente specificato; per esempio, una possibilità è che [[Get]]e [[Put]]per un particolare oggetto host effettivamente recuperi e memorizzi valori di proprietà ma [[HasProperty]]genera sempre false .

(Non sono riuscito a trovare la verbosità equivalente nella ES2015 specifiche, ma è destinata a essere ancora il caso.) Anche in questo caso, al momento della stesura del comune host fornito array come oggetti in browser moderni [ NodeListcasi, per esempio] fare manico [[HasProperty]]correttamente, ma è importante testarlo.)


44
Vorrei anche aggiungere che .forEachnon può essere rotto in modo efficiente. Devi lanciare un'eccezione per eseguire la pausa.
Pijusn,

82
@Pius: se vuoi interrompere il loop, puoi usare some. (Avrei preferito permettere anche la rottura forEach, ma loro, um, non me l'hanno chiesto. ;-))
TJ Crowder,

6
@TJCrowder Vero, anche se sembra più una soluzione poiché non è il suo scopo principale.
Pijusn,

8
@ user889030: hai bisogno di un ,dopo k=0, non di un ;. Ricorda, la programmazione è molte cose, una delle quali è una grande attenzione ai dettagli ... :-)
TJ Crowder,

5
@JimB: Questo è coperto sopra (e lengthnon è un metodo). :-)
TJ Crowder

513

Nota : 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 è un vanilla- forloop:

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

Si noti, tuttavia, che questo approccio è valido solo se si dispone di un array denso e ogni indice è occupato da un elemento. Se l'array è scarso, è possibile che si verifichino problemi di prestazioni con questo approccio, poiché si passerà in rassegna molti indici che non esistono realmente nell'array. In questo caso, un for .. in-loop potrebbe essere un'idea migliore. Tuttavia , è necessario utilizzare le garanzie appropriate per garantire che for..invengano applicate solo le proprietà desiderate dell'array (ovvero gli elementi dell'array), poiché -loop verrà anche elencato 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 JavaScript lato server) o utilizzare un "Polyfill". Il Polyfill per questa funzionalità è, tuttavia, banale e poiché semplifica la lettura del codice, è un buon polyfill da includere.


2
perché for(instance in objArray) non è un uso corretto? mi sembra più semplice, ma ho sentito che ne parli come un modo non corretto di utilizzo?
Dante1986,

21
È possibile utilizzare la memorizzazione nella cache della lunghezza in linea: for (var i = 0, l = arr.length; i <l; i ++)
Robert Hoffmann

3
La virgola alla fine della prima riga è intenzionale o è un refuso (potrebbe essere un punto e virgola)?
Mohd Abdul Mujib,

6
@ wardha-Web È intenzionale. Ci consente di dichiarare più variabili con una sola varparola chiave. Se avessimo usato un punto e virgola, elementsarebbe stato dichiarato nell'ambito globale (o, piuttosto, JSHint ci avrebbe urlato prima che raggiungesse la produzione).
PatrikAkerstrand,

239

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

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

MODIFICARE :

Come da domanda, l'utente desidera il codice in javascript anziché in jquery, quindi la modifica è

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

2
Probabilmente userò questa risposta il più delle volte. Non è la migliore risposta alla domanda, ma in pratica sarà la più semplice e la più applicabile per quelli di noi che usano jQuery. Penso che dovremmo comunque imparare tutti alla vaniglia. Non fa mai male espandere la tua comprensione.
mopsyd,

47
Solo per il gusto di farlo: jQuery è molto più lento delle soluzioni native. JQuery consiglia di utilizzare JavaScript nativo anziché jQuery ogni volta che è possibile. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss

8
Evita di usare jQuery quando puoi usare vanilla js
Noe

2
Attenersi a JS standard, mantenere le librerie di terze parti fuori dalla risposta a meno che non esista una soluzione in lingua nativa
scubasteve,

116

Ripeti indietro

Penso che il contrario di loop meriti una menzione qui:

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

vantaggi:

  • Non è necessario dichiarare una lenvariabile temporanea o confrontarla array.lengthcon ciascuna iterazione, una delle quali potrebbe essere un'ottimizzazione minuto.
  • La rimozione dei fratelli dal DOM in ordine inverso è generalmente più efficiente . (Il browser deve eseguire meno spostamenti di elementi nelle sue matrici interne.)
  • Se si modifica l'array durante il loop, in corrispondenza o dopo l'indice i (ad esempio rimuovendo o inserendo un elemento in array[i]), un loop in avanti salterebbe l'elemento che si spostava a sinistra in posizione i , oppure rielaborava il primo elemento che era spostato a destra. In un ciclo for tradizionale, è possibile aggiornare i per indicare l'elemento successivo che deve essere elaborato - 1, ma semplicemente invertire la direzione dell'iterazione è spesso una soluzione più semplice ed elegante .
  • Allo stesso modo, durante la modifica o la rimozione di elementi DOM nidificati , l'elaborazione inversa può aggirare gli errori . Ad esempio, prendere in considerazione la modifica di innerHTML di un nodo padre prima di gestirne i figli. Quando viene raggiunto, il nodo figlio verrà rimosso dal DOM, essendo stato sostituito da un figlio appena creato quando è stato scritto l'HTML interno del genitore.
  • È più breve da digitare e leggere rispetto ad alcune delle altre opzioni disponibili. Anche se perde da forEach()e verso ES6 for ... of.

svantaggi:

  • Elabora gli articoli in ordine inverso. Se stavi costruendo un nuovo array dai risultati o stampando cose sullo schermo, naturalmente l'output verrà invertito rispetto all'ordine originale.
  • Inserire ripetutamente fratelli nel DOM come primo figlio per mantenere il loro ordine è meno efficiente . (Il browser continuerebbe a dover spostare le cose nel modo giusto.) Per creare nodi DOM in modo efficiente e in ordine, basta andare avanti e indietro come al solito (e usare anche un "frammento di documento").
  • Il ciclo inverso è fonte di confusione per gli sviluppatori junior. (Puoi considerarlo un vantaggio, a seconda delle tue prospettive.)

Dovrei sempre usarlo?

Alcuni sviluppatori usano il reverse per loop per impostazione predefinita , a meno che non ci sia una buona ragione per andare avanti.

Sebbene i guadagni in termini di prestazioni siano generalmente insignificanti, in un certo senso urla:

"Fallo solo per ogni elemento della lista, non mi interessa l'ordine!"

Tuttavia, in pratica, che è non è in realtà un'indicazione affidabile di intenti, dal momento che è indistinguibile da quelle occasioni in cui si esegue la cura circa l'ordine, e davvero bisogno di anello in senso inverso. Quindi, in effetti, sarebbe necessario un altro costrutto per esprimere accuratamente l'intento di "non preoccuparsi", qualcosa attualmente non disponibile nella maggior parte delle lingue, incluso ECMAScript, ma che potrebbe essere chiamato, ad esempio forEachUnordered(),.

Se l'ordine non ha importanza e l' efficienza è una preoccupazione (nel ciclo più interno di un motore di gioco o di animazione), allora può essere accettabile usare il contrario per il ciclo come modello di partenza. Ricorda solo che vedere un reverse per loop nel codice esistente non significa necessariamente che l'ordine sia irrilevante!

Era meglio usare forEach ()

In generale, per un codice di livello superiore in cui la chiarezza e la sicurezza sono preoccupazioni maggiori, in precedenza ho raccomandato di utilizzare Array::forEachcome modello predefinito per il looping (anche se in questi giorni preferisco usare for..of). I motivi da preferire forEachrispetto a un ciclo inverso sono:

  • È più chiaro da leggere.
  • Esso indica che i non sta per essere spostato all'interno del blocco (che è sempre un possibile nascondiglio sorpresa nella lunga fore whileloop).
  • Ti dà un campo di applicazione gratuito per le chiusure.
  • Riduce la perdita di variabili locali e la collisione accidentale con (e mutazione di) variabili esterne.

Quindi quando vedi il reverse per loop nel tuo codice, questo è un suggerimento che è invertito per una buona ragione (forse uno dei motivi sopra descritti). E vedere un tradizionale forward for loop può indicare che può avvenire lo spostamento.

(Se la discussione sulle intenzioni non ha senso per te, allora tu e il tuo codice potreste trarre beneficio dalla visione della conferenza di Crockford su Stile di programmazione e cervello .)

Ora è ancora meglio usare per..of!

C'è un dibattito sull'opportunità for..ofo meno di forEach():

  • Per il massimo supporto del browser, è for..of necessario un polyfill per gli iteratori, rendendo l'app leggermente più lenta da eseguire e leggermente più grande da scaricare.

  • Per questo motivo (e per incoraggiare l'uso di mape filter), alcune guide di stile front-end vietano for..ofcompletamente!

  • Ma le preoccupazioni di cui sopra non sono applicabili alle applicazioni Node.js, dove for..ofora è ben supportato.

  • E inoltre await non funziona all'interno forEach(). L'uso for..ofè il modello più chiaro in questo caso.

Personalmente, tendo a usare ciò che sembra più facile da leggere, a meno che le prestazioni o la minificazione non siano diventate una delle maggiori preoccupazioni. Quindi in questi giorni preferisco usare for..ofinvece di forEach(), ma userò sempre mapo filtero findo somequando applicabile. (Per il bene dei miei colleghi, lo uso raramente reduce.)


Come funziona?

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

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

Noterai che i--è la clausola centrale (dove di solito vediamo un confronto) e l'ultima clausola è vuota (dove di solito vediamo i++). Ciò significa che i--viene utilizzato anche come condizione per la continuazione. Fondamentalmente, viene eseguito e verificato prima di ogni iterazione.

  • Come può iniziare array.lengthsenza esplodere?

    Poiché i--viene eseguito prima di ogni iterazione, alla prima iterazione accederemo effettivamente all'elemento per array.length - 1evitare problemi con gli elementi fuori campo dell'array undefined .

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

    Il ciclo interromperà l'iterazione quando la condizione i--restituisce un valore false (quando restituisce 0).

    Il trucco è che a differenza dell'operatore --ifinale i--diminuisce ima restituisce il valore prima del decremento. La tua console può dimostrarlo:

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

    [5, 5, 4]

    Quindi sulla iterazione finale, i stato precedentemente 1 e l' i--espressione cambia a 0 ma effettivamente rese 1 (truthy), e quindi la condizione passa. Alla successiva iterazione i--cambia i in -1 ma produce 0 (falsey), facendo sì che l'esecuzione cada immediatamente dal fondo del ciclo.

    Nel tradizionale forward per loop, i++e ++isono intercambiabili (come sottolinea Douglas Crockford). Tuttavia, al contrario per il ciclo, poiché il nostro decremento è anche la nostra espressione di condizione, dobbiamo attenerci i--se vogliamo elaborare l'articolo all'indice 0.


banalità

Ad alcune persone piace disegnare una piccola freccia nel forciclo inverso e terminare con un occhiolino:

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

I crediti vanno alla WYL per avermi mostrato i benefici e gli orrori del contrario per loop.


3
Ho dimenticato di aggiungere i parametri di riferimento . Ho anche dimenticato di menzionare come il reverse looping sia un'ottimizzazione significativa su processori a 8 bit come il 6502, dove puoi davvero ottenere il confronto gratuitamente!
joeytwiddle,

La stessa risposta è data molto più concisa qui (su una domanda diversa).
Joeytwiddle,

84

Alcuni linguaggi in stile C usano foreachper scorrere le enumerazioni. In JavaScript questo viene fatto con la for..instruttura del ciclo :

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

C'è un problema. for..inpasserà in rassegna ciascuno dei membri enumerabili dell'oggetto e i membri sul suo prototipo. Per evitare la lettura di valori ereditati tramite 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 forEachmetodo al Array.prototypequale può essere usato per enumerare un array usando un calback (il polyfill è nei documenti, quindi puoi ancora usarlo per i browser più vecchi):

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

È importante notare che Array.prototype.forEachnon si interrompe al ritorno della richiamata false. jQuery e Underscore.js forniscono le proprie variazioni eachper fornire loop che possono essere cortocircuitati.


3
Quindi come si fa a uscire da un ciclo foreach ECMAScript5 come faremmo per un normale ciclo for for o un ciclo foreach come quello trovato nei linguaggi in stile C?
Ciaran Gallagher,

5
@CiaranG, in JavaScript è comune vedere eachmetodi che consentono return falsedi essere utilizzati per uscire dal ciclo, ma con forEachquesto non è un'opzione. Potrebbe essere usato un flag esterno (cioè if (flag) return;, ma impedirebbe solo l'esecuzione del resto del corpo della funzione, forEachcontinuerebbe comunque a scorrere su tutta la raccolta.
zzzzBov

43

Se si desidera eseguire il loop su un array, utilizzare il forloop in tre parti standard .

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

È possibile ottenere alcune ottimizzazioni delle prestazioni memorizzando nella cache myArray.lengtho ripetendo al contrario.


6
per (var i = 0, length = myArray.length; i <length; i ++) dovrebbe farlo
Edson Medina

5
@EdsonMedina Questo creerà anche una nuova variabile globale chiamata length. ;)
joeytwiddle,

4
@joeytwiddle Sì, ma questo va oltre lo scopo di questo post. Creerai comunque una variabile globale.
Edson Medina,

6
@EdsonMedina Le mie scuse, ho sbagliato completamente. L'uso ,dopo un incarico non introduce un nuovo globale, quindi il tuo suggerimento è perfetto ! Lo stavo confondendo per un altro problema: l'utilizzo =dopo un incarico crea un nuovo globale.
joeytwiddle,

Attenzione alla variabile i non è locale al loop. JavaScript non ha ambito di blocco. Probabilmente è meglio dichiarare var i, length, arrayItem;prima del ciclo per evitare questo malinteso.
James,

35

So che questo è un vecchio post e ci sono già così tante grandi risposte. Per un po 'più di completezza ho pensato di aggiungerne un altro usando AngularJS . Ovviamente, questo vale solo se stai usando Angular, ovviamente, comunque mi piacerebbe metterlo comunque.

angular.forEachaccetta 2 argomenti e un terzo argomento facoltativo. Il primo argomento è l'oggetto (array) su cui eseguire l'iterazione, il secondo argomento è la funzione iteratore e il terzo argomento facoltativo è il contesto dell'oggetto (sostanzialmente definito 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 un array all'altro è

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 nell'usare la angular.forEachfunzione in contrapposizione al forloop incorporato al gusto di vaniglia .

Professionisti

  • Leggibilità facile
  • Facile da scrivere
  • Se disponibile, angular.forEachutilizzerà ES5 per ogni loop. Ora, raggiungerò l'efficienza nella sezione contro, poiché i loop forEach sono molto più lenti rispetto ai loop for. Lo cito come un professionista perché è bello essere coerenti e standardizzati.

Considera i seguenti 2 loop nidificati, che fanno esattamente la stessa cosa. Diciamo che abbiamo 2 matrici di oggetti e ogni oggetto contiene una matrice di risultati, ognuno dei quali ha una proprietà Value che è una stringa (o qualsiasi altra cosa). E diciamo che dobbiamo iterare 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
        }
    }
}

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

Contro

  • Efficienza. angular.forEache il nativo forEach, del resto, sono entrambi molto più lenti del normale forloop .... circa il 90% più lenti . Quindi, per insiemi di dati di grandi dimensioni, è meglio attenersi al forciclo nativo .
  • Nessuna interruzione, continua o restituisce supporto. continueè effettivamente supportato da " incidente ", per continuare in un angular.forEachsemplice mettere una return;dichiarazione nella funzione come angular.forEach(array, function(item) { if (someConditionIsTrue) return; });che lo farà uscire dalla funzione per quella iterazione. Ciò è dovuto anche al fatto che il nativo forEachnon supporta l'interruzione o continua.

Sono sicuro che ci sono anche altri pro e contro, e sentiti libero di aggiungere quello che ritieni opportuno. Sento che, in conclusione, se hai bisogno di efficienza, segui solo il forloop nativo per le tue esigenze di loop. Ma, se i tuoi set di dati sono più piccoli e un po 'di efficienza va bene rinunciare in cambio di leggibilità e scrivibilità, allora dai sicuramente angular.forEachquel cattivo ragazzo.


34

Se non ti dispiace svuotare l'array:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xconterrà l'ultimo valore di ye verrà rimosso dall'array. Puoi anche usare quello shift()che darà e rimuoverà il primo oggetto da y.


4
Non funziona se ti capita di avere una matrice sparsa come [1, 2, undefined, 3].
M. Grzywaczewski,

2
... o addirittura qualcosa di falso: [1, 2, 0, 3]o[true, true, false, true]
joeytwiddle,

31

Un forEach 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
  }
);

2
iteratore in questo, sta facendo un inutile calcolo della lunghezza. Nel caso ideale, la lunghezza dell'elenco dovrebbe essere calcolata una sola volta.
MIdhun Krishna il

2
@MIdhunKrishna Ho aggiornato la mia risposta e il jsFiddle ma tieni presente che non è così semplice come pensi. Controlla questa domanda
nmoliveira,

2
L'implementazione completa e corretta è disponibile qui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
marciowb

29

Probabilmente il for(i = 0; i < array.length; i++)loop non è la scelta migliore. Perché? Se hai questo:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

Il metodo chiamerà da array[0]a array[2]. Innanzitutto, questo farà prima riferimento alle variabili che non hai nemmeno, in secondo luogo non avresti le variabili nell'array, e in terzo luogo renderà il codice più audace. Guarda qui, è quello che uso:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

E se vuoi che sia una funzione, puoi farlo:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

Se vuoi rompere, un po 'più di logica:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

Esempio:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Restituisce:

//Hello
//World
//!!!

29

Esistono tre implementazioni di foreachin jQuery come segue.

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3

2
Il registro della console è solo per la demo. Questo per renderlo un esempio in esecuzione cmplete.
Rajesh Paul,

29

A partire da ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

Dove ofevita le stranezze associate ine lo fa funzionare come il forciclo di qualsiasi altra lingua, e si letlega iall'interno del ciclo invece che all'interno della funzione.

Le parentesi graffe ( {}) possono essere omesse quando esiste un solo comando (ad esempio nell'esempio sopra).


28

Una soluzione semplice ora sarebbe usare la libreria underscore.js . Fornisce molti strumenti utili, come eache delegherà automaticamente il lavoro al nativo, forEachse disponibile.

Un esempio di CodePen di come funziona è:

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

Guarda anche


23

Non esiste alcun for eachciclo in JavaScript nativo . È possibile utilizzare le librerie per ottenere questa funzionalità (consiglio Underscore.js ), utilizzare un semplice forciclo.

for (var instance in objects) {
   ...
}

Tuttavia, tieni presente che potrebbero esserci dei motivi per utilizzare un forciclo ancora più semplice (vedi la domanda Stack Overflow Perché usare "for ... in" con l'iterazione dell'array è una cattiva idea? )

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

22

Questo è un iteratore per l'elenco NON sparse in cui l'indice inizia da 0, che è lo scenario tipico quando si tratta di document.getElementsByTagName o document.querySelectorAll)

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

Esempi di utilizzo:

Esempio 1

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

Esempio n. 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Ogni tag p viene visualizzato class="blue"

Esempio n. 3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

Ogni altro tag p viene visualizzato class="red">

Esempio n. 4

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

E infine i primi 20 tag p blu vengono cambiati in verde

Attenzione quando si utilizza la stringa come funzione: la funzione viene creata fuori contesto e deve essere utilizzata solo dove si è certi dell'ambito variabile. Altrimenti, è meglio passare funzioni in cui l'ambito è più intuitivo.


21

Esistono alcuni modi per eseguire il looping di un array in JavaScript, come di seguito:

per - è il più comune . Blocco completo di codice per il looping

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

while - loop mentre una condizione è passata. Sembra essere il ciclo più veloce

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while : esegue anche il ciclo di un blocco di codice mentre la condizione è vera, verrà eseguita almeno una volta

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

Loop funzionali - forEach, map, filter, anche reduce(loro ciclo attraverso la funzione, ma sono utilizzati se avete bisogno di fare qualcosa con la matrice, etc.

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

Per ulteriori informazioni ed esempi sulla programmazione funzionale su array, consultare il post sul blog Programmazione funzionale in JavaScript: mappa, filtro e riduzione .


Piccola correzione: forEachnon è un ciclo "funzionale" poiché non restituisce un nuovo Array(in realtà non restituisce nulla), ma solo itera.
Nicholaswmin,

19

ECMAScript 5 (la versione su JavaScript) per lavorare con gli array:

forEach : scorre ogni elemento dell'array e fa tutto il necessario con ogni elemento.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

Nel caso, più interessato al funzionamento sull'array utilizzando alcune funzionalità integrate.

map : crea un nuovo array con il risultato della funzione di callback. Questo metodo è utile quando è necessario formattare gli elementi dell'array.

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

ridurre - Come dice il nome, riduce l'array a un singolo valore chiamando la funzione data passando nell'elemento corrente e il risultato dell'esecuzione precedente.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

ogni - Restituisce vero o falso se tutti gli elementi dell'array superano il test nella funzione di callback.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filtro - Molto simile a tutti tranne che quel filtro restituisce un array con gli elementi che restituiscono true alla data funzione.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

16

Non esiste alcuna capacità incorporata di irrompere forEach. Per interrompere l'esecuzione, utilizzare Array#somecome di seguito:

[1,2,3].some(function(number) {
    return number === 1;
});

Questo funziona perché somerestituisce true non appena uno qualsiasi dei callback, eseguito in ordine di array, restituisce true, cortocircuitando l'esecuzione del resto. Risposta originale vedi prototipo di array per alcuni


13

Vorrei anche aggiungere questo come composizione di un ciclo inverso e una risposta sopra per qualcuno che vorrebbe anche questa sintassi.

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

Professionisti:

Il vantaggio per questo: hai già il riferimento nel primo tipo che non dovrà essere dichiarato in seguito con un'altra riga. È utile quando si esegue il looping attraverso l'array di oggetti.

Contro:

Questo si interromperà ogni volta che il riferimento è falso - falso (indefinito, ecc.). Può essere usato come un vantaggio però. Tuttavia, renderebbe un po 'più difficile la lettura. E anche a seconda del browser può essere "non" ottimizzato per funzionare più velocemente di quello originale.


12

Modo jQuery usando $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

1
Penso che l'output abbia maggiori probabilità di esserlo [undefined, 2, undefined, 4, undefined, 6, undefined].

10

Utilizzo di loop con ECMAScript 6 destructuring e l' operatore spread

La distruzione e l'utilizzo dell'operatore di diffusione si sono dimostrati abbastanza utili per i nuovi arrivati ​​a ECMAScript 6 come più leggibili / estetici, sebbene alcuni veterani di JavaScript possano considerarlo disordinato. Juniors o altre persone potrebbero trovarlo utile.

Gli esempi seguenti useranno l' for...ofistruzione e il .forEachmetodo.

Esempi 6, 7 e 8 possono essere utilizzati con qualsiasi cicli funzionali come .map, .filter, .reduce, .sort, .every, .some. Per ulteriori informazioni su questi metodi, controlla l' Array Object .

Esempio 1:for...of loop normale - nessun trucco qui.

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

Esempio 2: dividere le parole in caratteri

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Esempio 3: loop con a keyevalue

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

Esempio 4: ottenere le proprietà degli oggetti in linea

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Esempio 5: ottenere le proprietà degli oggetti profondi di ciò che è necessario

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Esempio 6: viene utilizzato l' esempio 3 con.forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

Esempio 7: viene utilizzato l' esempio 4 con.forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

Esempio 8: viene utilizzato l' esempio 5 con.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


7

Un modo più vicino alla tua idea sarebbe usare Array.forEach()che accetta una funzione di chiusura che verrà eseguita per ogni elemento dell'array.

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

Un altro modo possibile sarebbe usare quello Array.map()che funziona allo stesso modo, ma prende anche tutti i valori restituiti e li restituisce in un nuovo array (essenzialmente mappando ogni elemento su uno nuovo), in questo modo:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

1
Questo è errato, mapnon muta gli elementi dell'array, perché restituisce un nuovo array, con gli elementi di quello nuovo come risultato dell'applicazione della funzione agli elementi del vecchio array.
Jesús Franco,

Non ho mai detto che non restituisce un nuovo array, mi riferivo al cambiamento applicato dalla funzione. Ma qui lo cambierò nella risposta.
Ante Jablan Adamović,

di nuovo sbagliato, la mappa non modifica o muta in alcun modo gli elementi dell'array originale, ho proposto e modificato la risposta sottolineando che la mappa funziona con una copia degli oggetti originali, lasciando intatto l'array originale
Jesús Franco

7

Puoi chiamare Ciascuno in questo modo:

forEacheseguirà l'iterazione sull'array fornito e per ogni iterazione che avrà elementil valore di tale iterazione. Se hai bisogno di un indice, puoi ottenere l'indice corrente passando ili il secondo parametro nella funzione di callback per forEach.

Foreach è fondamentalmente una funzione di ordine elevato, che accetta un'altra funzione come parametro.

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

Produzione:

1
3
2

Puoi anche scorrere su un array come questo:

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}

6

Se si desidera eseguire il ciclo attraverso una matrice di oggetti con la funzione freccia:

let arr = [{name:'john', age:50}, {name:'clark', age:19}, {name:'mohan', age:26}];

arr.forEach((person)=>{
  console.log('I am ' + person.name + ' and I am ' + person.age + ' old');
})


6

La sintassi lambda di solito non funziona in Internet Explorer 10 o versioni precedenti.

Di solito uso il

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

Se sei un fan di jQuery e hai già un file jQuery in esecuzione, dovresti invertire le posizioni dell'indice e dei parametri del valore

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

5

Se disponi di un array enorme, dovresti utilizzare iteratorsper ottenere un po 'di efficienza. Gli iteratori sono una proprietà di alcune collezioni JavaScript (come Map, Set, String, Array). Anche, for..ofusaiterator sotto il cofano.

Gli iteratori migliorano l'efficienza permettendoti di consumare gli elementi in un elenco uno alla volta come se fossero uno stream. Ciò che rende speciale un iteratore è il modo in cui attraversa una raccolta. Altri loop devono caricare l'intera raccolta in primo piano per iterare su di essa, mentre un iteratore deve solo conoscere la posizione corrente nella raccolta.

Puoi accedere all'elemento corrente chiamando il nextmetodo dell'iteratore . Il metodo successivo restituirà l' valueoggetto corrente e a booleanper indicare quando hai raggiunto la fine della raccolta. Di seguito è riportato un esempio di creazione di un iteratore da un array.

Trasforma il tuo array normale in iteratore usando values()questo metodo:

    const myArr = [2,3,4]

let it = myArr.values();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Puoi anche trasformare il tuo array normale in iteratore usando in Symbol.iteratorquesto modo:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Puoi anche trasformare il tuo normale arrayin uno iteratorcome questo:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

NOTA :

  • Gli iteratori sono di natura esauribile.
  • Gli oggetti non sono iterabledi default. Utilizzare for..inin quel caso perché invece di valori funziona con le chiavi.

Puoi leggere di più iteration protocol qui .


5

Se vuoi usare forEach(), sembrerà -

theArray.forEach ( element => {
    console.log(element);
});

Se vuoi usare for(), sembrerà -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

4

Come per la nuova funzionalità aggiornata ECMAScript 6 (ES6) e ECMAScript 2015, è possibile utilizzare le seguenti opzioni con i loop:

per i loop

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

per ... in loop

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach ()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

per ... di anelli

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

mentre loops

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

fare ... mentre loops

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

4

Prestazione

Oggi (18-12-2019) eseguo test sul mio macOS v10.13.6 (High Sierra), su Chrome v 79.0, Safari v13.0.4 e Firefox v71.0 (64 bit) - conclusioni sull'ottimizzazione (e micro-ottimizzazione che di solito non vale la pena introdurlo al codice perché il vantaggio è piccolo, ma la complessità del codice aumenta).

  • Sembra che il tradizionale for i( Aa ) sia una buona scelta per scrivere codice veloce su tutti i browser.

  • Le altre soluzioni, come for-of( Ad ), tutte nel gruppo C. ... di solito sono 2 - 10 (e più) volte più lente di Aa , ma per array di piccole dimensioni è accettabile usarlo - per motivi di maggiore chiarezza del codice.

  • I loop con lunghezza della matrice memorizzata nella cache n( Ab, Bb, Be ) sono a volte più veloci, a volte no. Probabilmente i compilatori rilevano automaticamente questa situazione e introducono la memorizzazione nella cache. Le differenze di velocità tra le versioni cache e no-cache ( Aa, Ba, Bd ) sono circa ~ 1%, quindi sembra che introdurre nsia una micro-ottimizzazione .

  • Le i--soluzioni simili in cui il ciclo inizia dall'ultimo elemento dell'array ( Ac, Bc ) sono in genere circa il 30% più lente rispetto alle soluzioni forward - probabilmente il motivo è il modo in cui la cache della memoria CPU funziona - la lettura della memoria forward è più ottimale per la cache della CPU). Si consiglia di NON UTILIZZARE tali soluzioni.

Dettagli

Nei test calcoliamo la somma degli elementi dell'array. Eseguo un test per array di piccole dimensioni (10 elementi) e array di grandi dimensioni (elementi 1M) e li divido in tre gruppi:

  • A - fortest
  • B - whiletest
  • C - altri / metodi alternativi

Risultati cross-browser

Risultati per tutti i browser testati

Inserisci qui la descrizione dell'immaginebrowser **

Matrice con 10 elementi

Risultati per Chrome. Puoi eseguire il test sulla tua macchina qui .

Inserisci qui la descrizione dell'immagine

Matrice con 1.000.000 di elementi

Risultati per Chrome. Puoi eseguire il test sulla tua macchina qui

Inserisci qui la descrizione dell'immagine


4

Sommario:

Quando si esegue l'iterazione su un array, spesso si desidera raggiungere uno dei seguenti obiettivi:

  1. Vogliamo iterare sull'array e creare un nuovo array:

    Array.prototype.map

  2. Vogliamo iterare sull'array e non creare un nuovo array:

    Array.prototype.forEach

    for..of ciclo continuo

In JavaScript, ci sono molti modi per raggiungere entrambi questi obiettivi. Tuttavia, alcuni sono più convenienti di altri. Di seguito puoi trovare alcuni metodi comunemente usati (l'IMO più conveniente) per realizzare l'iterazione dell'array in JavaScript.

Creazione di un nuovo array: Map

map()è una funzione su Array.prototypecui è possibile trasformare ogni elemento di un array e quindi restituire un nuovo array. map()accetta come argomento una funzione di callback e funziona nel modo seguente:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

Il callback che abbiamo passato map()come argomento viene eseguito per ogni elemento. Quindi viene restituito un array che ha la stessa lunghezza dell'array originale. In questo nuovo elemento dell'array viene trasformato dalla funzione di callback passata come argomento a map().

La differenza netta tra mape un altro meccanismo di loop simile forEache un for..ofloop è che maprestituisce un nuovo array e lascia intatto il vecchio array (tranne se lo si manipola esplicitamente consplice ).

Si noti inoltre che il mapcallback della funzione fornisce il numero di indice dell'iterazione corrente come secondo argomento. Inoltre, il terzo argomento fornisce l'array su cui è mapstato chiamato? A volte queste proprietà possono essere molto utili.

Usare il ciclo forEach

forEachè una funzione su cui si trova Array.prototypeuna funzione di callback come argomento. Quindi esegue questa funzione di callback per ogni elemento dell'array. Contrariamente alla map()funzione, la funzione forEach non restituisce nulla ( undefined). Per esempio:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

Proprio come la mapfunzione, il forEachcallback fornisce il numero di indice dell'iterazione corrente come secondo argomento. Inoltre, il terzo argomento fornisce l'array su cui è forEachstato chiamato?

Passa attraverso gli elementi usando for..of

Il for..ofciclo scorre attraverso ogni elemento di un array (o qualsiasi altro oggetto iterabile). Funziona nel modo seguente:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

Nell'esempio sopra, elementsta per un elemento array ed arrè l'array che vogliamo eseguire in loop. Nota che il nome elementè arbitrario e avremmo potuto scegliere qualsiasi altro nome come 'el' o qualcosa di più dichiarativo quando questo è applicabile.

Non confondere il for..inloop con il for..ofloop. for..ineseguirà il ciclo attraverso tutte le proprietà enumerabili dell'array mentre il for..ofciclo eseguirà il ciclo solo attraverso gli elementi dell'array. Per esempio:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.