2014-05-12 8 views
87

che ho visto di domande che suggerisco di usare:JavaScript - Sfumature di myArray.forEach vs abbondanza per ciclo

for (var i = 0; i < myArray.length; i++){ /* ... */ } 

invece di:

for (var i in myArray){ /* ... */ } 

per gli array, a causa di iterazione incoerente (see here).


Tuttavia, non riesco a trovare nulla che sembra preferire l'oggetto ciclo orientato:

myArray.forEach(function(item, index){ /* ... */ }); 

che sembra modo più intuitivo per me.

Per il mio progetto attuale, IE8 compatibilità è importante, e sto pensando di utilizzare Mozilla's polyfill, però io non sono sicuro al 100% di come questo funzionerà.

  • Ci sono delle differenze tra lo standard per ciclo (il primo esempio di cui sopra) e l'attuazione Array.prototype.forEach dai browser moderni?
  • C'è qualche differenza tra le moderne implementazioni del browser e l'implementazione di Mozilla collegata a sopra (con particolare riguardo a IE8)?
  • Le prestazioni non sono un problema, ma solo la coerenza con le proprietà iterate.
+6

Non è possibile 'break' di' forEach'. Ma un grande vantaggio è creare un nuovo scope con la funzione. Con il polyfill non dovresti avere problemi (almeno non ne ho incontrato nessuno). – hgoebl

+0

I problemi che si possono avere con IE precedente, non sono lo shim stesso, ma il costruttore dell'array rotto/letterale 'fori' dove' indefinito' dovrebbe essere e altri metodi rotti, come 'slice' e' hasOwnProperty' wrt in DOM arraylike oggetti. I miei test e ['es5 shim'] (https://github.com/es-shims/es5-shim) hanno dimostrato che i metodi di spalmatura sono conformi alla specifica (non testato lo shim di MDN). – Xotic750

+1

E a rompere con un ciclo 'for', questo è ciò che [' some'] (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some) è per . – Xotic750

risposta

120

La differenza più sostanziale tra la for loop e il metodo forEach è che, con l'ex, si può break fuori dal giro. È possibile simulare continue semplicemente ritornando dalla funzione passata a forEach, ma non è possibile arrestare del tutto il ciclo.

A parte questo, i due realizzano efficacemente la stessa funzionalità. Un'altra piccola differenza riguarda l'ambito dell'indice (e tutte le variabili contenenti) nel ciclo for, a causa del sollevamento variabile.

// 'i' is scoped to the containing function 
for (var i = 0; i < arr.length; i++) { ... } 

// 'i' is scoped to the internal function 
arr.forEach(function (el, i) { ... }); 

Tuttavia, trovo che forEach è molto più espressivo-che rappresenta l'intenzione di scorrere ogni elemento di un array, e fornisce un riferimento all'elemento, non solo l'indice. Nel complesso, si tratta principalmente di gusti personali, ma se è possibile utilizzare forEach, si consiglia di utilizzarlo.


ci sono un paio di differenze sostanziali tra le due versioni, in particolare per quanto riguarda le prestazioni. In effetti, il ciclo for semplice ha prestazioni notevolmente migliori rispetto al metodo forEach, come dimostrato da this jsperf test.

Se tale prestazione è necessaria o meno per voi dipende da voi decidere, e nella maggior parte dei casi, vorrei favorire espressività su velocità. Questa differenza di velocità è probabilmente dovuta alle minori differenze semantiche tra il loop di base e il metodo quando si opera su array sparsi, come indicato in this answer.

Se non è necessario il comportamento di forEach e/o avete bisogno di uscire dal giro iniziale, è possibile utilizzare Lo-Dash di _.each in alternativa, che sarà anche il lavoro cross-browser.Se si utilizza jQuery, fornisce anche un valore simile a $.each, si noti solo le differenze tra gli argomenti passati alla funzione di callback in ciascuna variante.

(Per quanto riguarda il forEach polyfill, dovrebbe funzionare in browser più vecchi senza problemi, se si sceglie di seguire questa strada.)

+1

Vale la pena notare che le versioni di libreria 'each' non si comportano nello stesso modo di ECMA5 specifica di 'forEach', tendono a trattare tutti gli array come densi (per evitare i bug di IE, a condizione che tu ne sia a conoscenza). Può essere un "gotcha" altrimenti. Come riferimento https://github.com/es-shims/es5-shim/issues/190 – Xotic750

+7

Esistono anche alcuni metodi di prototipo che consentono di rompere come 'Array.prototype.some' che si interrompe finché non si restituisce un valore di verità o fino a quando non ha completato il ciclo attraverso la matrice. 'Array.prototype.every' è simile a' Array.prototype.some' ma si arresta se si restituisce un valore di falsy. – axelduch

+0

Se vuoi vedere alcuni risultati di test su diversi browser e shim, puoi dare un'occhiata qui, https://ci.testling.com/Xotic750/util-x – Xotic750

4

Si è suggerito da alcuni sviluppatori (ad esempio, Kyle Simpson) da utilizzare .forEach per indicare che la matrice avrà un effetto collaterale e .map per le funzioni pure. for loop in questa equazione, quindi, a mio parere, rientrano in questa equazione come una soluzione generica che è più facile da comunicare in quanto è supportata su una pletora di lingue esp quando il # di iterazioni è precalcolata.

11

È possibile utilizzare la funzione foreach personalizzato che si esibirà molto meglio allora Array.forEach

Si dovrebbe aggiungere questa volta per il codice. Questo aggiungerà una nuova funzione alla matrice.

function foreach(fn) { 
    var arr = this; 
    var len = arr.length; 
    for(var i=0; i<len; ++i) { 
     fn(arr[i], i); 
    } 
} 

Object.defineProperty(Array.prototype, 'customForEach', { 
    enumerable: false, 
    value: foreach 
}); 

Quindi si può usare ovunque come l'Array.forEach

[1,2,3].customForEach(function(val, i){ 

}); 

L'unica differenza è 3 volte più veloce. https://jsperf.com/native-arr-foreach-vs-custom-foreach

AGGIORNAMENTO: nella nuova versione di Chrome le prestazioni di .forEach() sono state migliorate. Tuttavia, la soluzione può fornire prestazioni aggiuntive in altri browser.

JSPerf