foreach javascript




Per-su un array in JavaScript? (19)

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.


Loop indietro

Penso che il reverse per loop meriti una menzione qui:

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

vantaggi:

  • Non è necessario dichiarare una variabile len temporanea o confrontarla con array.length a ogni iterazione, che potrebbe essere una ottimizzazione minima.
  • Rimozione di fratelli dal DOM in ordine inverso è di solito più efficiente . (Il browser deve fare meno spostamento degli elementi nei suoi array interni).
  • Se si modifica la matrice durante il ciclo, a o dopo l'indice i (ad esempio si rimuove o si inserisce un elemento array[i] ), un ciclo in avanti salta l'elemento spostato a sinistra in posizione i , oppure rielabora i l'oggetto che è stato spostato a destra. In un ciclo for tradizionale, è possibile aggiornare i per puntare all'elemento successivo che richiede l'elaborazione - 1, ma invertire semplicemente la direzione dell'iterazione è spesso una soluzione più semplice ed elegante .
  • Allo stesso modo, quando si modificano o si rimuovono gli elementi DOM nidificati , l'elaborazione al contrario può 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 da digitare e leggere , rispetto ad alcune delle altre opzioni disponibili. Anche se perde per forEach() e per ES6 for ... of .

svantaggi:

  • Elabora gli articoli in ordine inverso. Se stavi creando un nuovo array dai risultati, o stampando cose sullo schermo, naturalmente l'output sarà invertito 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 è fonte di confusione per gli sviluppatori junior. (Puoi considerare che un vantaggio, a seconda della tua prospettiva.)

Dovrei sempre usarlo?

Alcuni sviluppatori utilizzano il ciclo inverso per impostazione predefinita , a meno che non vi sia una buona ragione per eseguire il ciclo 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!"

Tuttavia, in pratica, questo non è in realtà un indicatore affidabile di intento, poiché non è distinguibile da quelle occasioni in cui ti interessi per l'ordine, e in realtà è necessario eseguire il ciclo al contrario. 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 l' efficienza è un problema (nel ciclo più interno di un motore di gioco o di animazione), può essere accettabile utilizzare il ciclo inverso come schema di partenza. Ricorda solo che vedere un'inversione di loop nel codice esistente non significa necessariamente che l'ordine sia irrilevante!

È meglio usare forEach ()

In generale per codici di livello superiore in cui chiarezza e sicurezza sono problemi maggiori, ti consiglio di utilizzare Array::forEach come schema predefinito:

  • È chiaro da leggere.
  • Indica che non ho intenzione di essere spostato all'interno del blocco (che è sempre una possibile sorpresa che si nasconde in loop lunghi e continui).
  • 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 su Programming Style e Your Brain .)

Come funziona?

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

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

Noterai che 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 condizione per la continuazione. Fondamentalmente, viene eseguito e controllato prima di ogni iterazione.

  • Come può iniziare a array.length senza esplodere?

    Siccome i-- viene eseguito prima di ogni iterazione, alla prima iterazione effettivamente array.length - 1 all'elemento in array.length - 1 che evita qualsiasi problema con gli elementi undefined Array-out-of-bounds .

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

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

    Il trucco è che a differenza di --i , il trailing i-- operator decrementa i ma restituisce il valore prima del decremento. La tua console può dimostrarlo:

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

    [5, 5, 4]

    Quindi, nell'ultima iterazione, ero precedentemente 1 e l'espressione i-- cambia a 0 ma in realtà produce 1 (verità), e quindi la condizione passa. Alla successiva iterazione i-- cambia i in -1 ma restituisce 0 (falsey), causando l'eliminazione immediata del fondo del ciclo.

    Nel tradizionale ciclo forwards, i++ e ++i sono intercambiabili (come fa notare Douglas Crockford). Comunque al contrario per loop, perché il nostro decremento è anche la nostra espressione di condizione, dobbiamo attenerci a i-- se vogliamo elaborare l'elemento all'indice 0.

banalità

Ad alcune persone piace disegnare una piccola freccia sul retro for ciclo e terminare 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.


Sommario:

Durante l'iterazione su un array, spesso è possibile 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 JS ci sono molti modi per raggiungere entrambi questi obiettivi. Tuttavia, alcuni sono più competenti di altri. Di seguito è possibile trovare alcuni metodi comunemente utilizzati (il più convinto) per eseguire 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 restituisce un nuovo array. map()prende 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 di matrice viene trasformato dalla funzione di callback passata come argomento a map().

La netta differenza tra mape un altro meccanismo di loop come forEache un for..ofloop sono che mapritorna come nuovo array e lascia intatto il vecchio array (eccetto se lo si manipola esplicitamente con pensieri simili splice).

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

Loop usando forEach

forEachè una funzione su Array.prototypecui si basa una funzione di callback come argomento. Quindi esegue questa funzione di callback per ogni elemento dell'array. In contrasto con la map()funzione, la funzione forEach 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 come secondo argomento il numero di indice dell'iterazione corrente. Inoltre, il terzo argomento fornisce l'array su cui è forEachstato chiamato.

Passa attraverso gli elementi usando for..of

Il for..ofloop 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 precedente elementsta per un elemento dell'array ed arrè l'array che vogliamo fare il ciclo. Non che il nome elementsia arbitrario e potremmo aver scelto qualsiasi altro nome come "el" o qualcosa di più dichiarativo quando questo è applicabile.

Non confondere il for..inciclo con il for..ofciclo. for..inpasserà in rassegna tutte le proprietà enumerabili dell'array mentre il for..ofciclo passerà 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);
}


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 verrà rimosso dall'array. Puoi anche usare shift() che darà e rimuoverà il primo elemento da y .


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

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

È possibile ottenere alcune ottimizzazioni delle prestazioni memorizzando myArray.length cache myArray.length o myArray.length al contrario.


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

angular.forEachprende 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 vantaggi e svantaggi nell'usare la angular.forEachfunzione in contrasto con il forloop integrato al gusto di vaniglia .

Professionisti

  • Facile leggibilità
  • Facile scrivibilità
  • Se disponibile, angular.forEachutilizzerà il ciclo ESE forEach. Ora, arriverò all'efficacia nella sezione contro, poiché i cicli di Everybody sono molto più lenti 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 ed era molto difficile da leggere e scrivere per quella materia.

Contro

  • Efficienza. angular.forEache il nativo forEach, peraltro, è molto più lento del normale forloop .... circa il 90% più lento . Pertanto, per i set di dati di grandi dimensioni, è meglio attenersi al forciclo nativo .
  • Nessuna interruzione, continuazione o restituzione del supporto. continueè effettivamente supportato da " accident ", per continuare in un modo angular.forEachsemplice inserire una return;dichiarazione nella funzione come la angular.forEach(array, function(item) { if (someConditionIsTrue) return; });quale farà sì che continui fuori dalla funzione per quella iterazione. Ciò è dovuto anche al fatto che il nativo forEachnon supporta né interrompe né continua.

Sono sicuro che ci sono anche altri pro e contro, e per favore sentiti libero di aggiungere qualsiasi cosa tu ritenga opportuno. Ritengo che, in conclusione, se hai bisogno di efficienza, segui semplicemente il forciclo nativo per le tue esigenze di ciclo. Ma, se i tuoi set di dati sono più piccoli e un po 'di efficienza va bene a rinunciare in cambio di leggibilità e scrivibilità, allora con tutti i mezzi gettare un angular.forEachin quel ragazzo cattivo.


A partire da ES6:

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

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

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


TL; DR

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

    • un ciclo for-of (solo ES2015 +),
    • Array#forEach ( spec | MDN ) (oi relativi parenti some e such) (solo ES5 +),
    • un semplice ciclo vecchio stile,
    • o for-in con le misure di sicurezza.

Ma c'è molto altro 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 matrici originali e opzioni per cose che sono semplicemente come una matrice, come l'oggetto arguments , altri oggetti iterabili (ES2015 +), raccolte DOM e così via.

Presto notare che ora è possibile utilizzare le opzioni ES2015, anche sui motori ES5, trasponendo ES2015 a ES5. Cerca "ES2015 transpiling" / "ES6 transpiling" per altro ...

Ok, diamo un'occhiata alle nostre opzioni:

Per array effettivi

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

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

Dettagli:

1. Utilizzare forEach e correlati

In qualsiasi ambiente vagamente moderno (quindi, non IE8) in cui si ha accesso alle funzionalità di Array aggiunte da ES5 (direttamente o utilizzando polifivoli), è 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 della stesura di questo articolo a settembre 2016), puoi tranquillamente utilizzare forEach in una pagina Web generica senza uno shim. Se hai bisogno di supportare browser obsoleti, forEach / 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; blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html

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 il callback restituisce false o qualcosa di falso)
  • some (interrompe il ciclo la prima volta che il callback restituisce true o qualcosa di vero)
  • filter (crea un nuovo array che include elementi in cui la funzione filter restituisce true e omette quelli in cui restituisce 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 reduce (come reduce , ma funziona in ordine discendente anziché ascendente)

2. Utilizzare un ciclo for semplice

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 cambierà durante il ciclo, ed è in un codice sensibile alle prestazioni (improbabile), una versione leggermente più complicata che cattura la lunghezza in avanti potrebbe essere 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, puoi rendere l'indice e le variabili di valore locali al ciclo for :

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 il value ma anche l' index viene ricreato per ogni iterazione del ciclo, il che significa che le chiusure create nel corpo del ciclo mantengono un riferimento index (e al 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 non funziona se usi var invece di let .

3. Usa il modo giusto for-in entrare

Avrai gente che ti dirà di usare for-in , ma non è quello che l' for-in for è per . cicli for-in attraverso le 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 (tramite [[OwnPropertyKeys]] , [[Enumerate]] e cose che li usano come Object.getOwnPropertyKeys ), ma non definisce che for-in seguirà quell'ordine. (Dettagli in questa altra risposta .)

Tuttavia, può essere utile, in particolare per gli array sparsi , se si utilizzano misure di salvaguardia 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 la sua proprietà con quel nome (non uno 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. Il motivo per cui è 2 ^ 32 - 2 è quello che rende il valore di indice più grande uno inferiore a 2 ^ 32 - 1 , che è il valore massimo che può avere una length dell'array. (Ad esempio, la lunghezza di una matrice si adatta a un intero senza segno a 32 bit.) (Puntando su RobG per aver indicato in un commento sul mio post sul blog che il mio test precedente non era del tutto corretto).

Questo è un po 'di overhead aggiunto per iterazione di loop sulla maggior parte degli array, ma se si dispone di un array sparse , può essere un modo più efficiente di eseguire il ciclo perché si limitano solo alle voci effettivamente esistenti. Ad esempio, per l'array sopra, facciamo un ciclo totale di tre volte (per le chiavi "0" , "10" e "10000" - ricorda che 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. Utilizzare for-of (utilizzare un iteratore implicitamente) (ES2015 +)

ES2015 aggiunge iteratori a JavaScript. Il modo più semplice per usare gli iteratori è la nuova dichiarazione for-of . Sembra questo:

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

Produzione:

a
b
c

Sotto le copertine, ottiene un iteratore dall'array e scorre attraverso di esso, ottenendo i valori da esso. Questo non ha il problema che usa for-in , 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 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 in modo esplicito . Puoi farlo anche se è molto più clunkier che 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. Il suo next metodo restituisce un nuovo oggetto risultato ogni volta che lo chiami. L'oggetto risultato ha una proprietà, done , che ci dice se è stata eseguita e un value proprietà con il valore per tale iterazione. ( done è facoltativo se sarebbe false , il value è facoltativo se non fosse undefined ).

Il significato del 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 ogni value è la voce dell'array per tale iterazione ( "a" , "b" e "c" nell'esempio precedente).
  • keys() : restituisce un iteratore in cui ogni value è la chiave per tale iterazione (quindi per il nostro a sopra, che sarebbe "0" , quindi "1" , quindi "2" ).
  • entries() : restituisce un iteratore in cui ogni value è una matrice nella forma [key, value] per tale iterazione.

Per oggetti tipo array

A parte i veri array, ci sono anche oggetti di tipo array che hanno una proprietà length e proprietà con nomi numerici: istanze NodeList , oggetti arguments , 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. Utilizza forEach e correlati (ES5 +)

    Le varie funzioni su Array.prototype sono "intenzionalmente generiche" e di solito possono essere utilizzate su oggetti di tipo array tramite la Function#call Function#apply o la Function#apply . (Vedi l' avvertenza per gli oggetti forniti dall'host alla fine di questa risposta, ma è un problema raro.)

    Si supponga di voler utilizzare forEach sulla proprietà forEach un Node . Faresti questo:

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

    Se lo farai molto, potresti voler prendere una copia del riferimento alla 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. Utilizzare un ciclo for semplice

    Ovviamente, un ciclo for semplice si applica a oggetti di tipo array.

  3. Usa correttamente il for-in

    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. Utilizzare 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 NodeList da querySelectorAll stata aggiornata per supportare l'iterazione. La specifica per HTMLCollection da getElementsByTagName non lo 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 metodo slice degli array

    Possiamo usare il metodo slice degli array, che come gli altri metodi menzionati sopra è "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"));
    

    Vedi il Caveat per gli oggetti forniti dall'host sotto. In particolare, si noti che ciò non funzionerà in IE8 e versioni precedenti, che non consentono di utilizzare oggetti forniti dall'host in this modo.

  2. Usa la sintassi di diffusione ( ... )

    È anche possibile utilizzare la sintassi di diffusione di ES2015 con i 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. Usa 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 si utilizzano Array.prototype funzioni Array.prototype con oggetti tipo array forniti dall'host (elenchi DOM e altri elementi forniti dal browser anziché dal motore JavaScript), è necessario assicurarsi di eseguire il test negli ambienti di destinazione per assicurarsi che l'host fornito l'oggetto si comporta correttamente. La maggior parte si comporta correttamente (ora), ma è importante testare. Il motivo è che la maggior parte dei metodi Array.prototype che si desidera utilizzare dipendono dall'oggetto fornito dall'host che fornisce una risposta onesta all'operazione [[HasProperty]] astratta. 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. È in §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à è che [[Get]] e [[Put]] per un particolare oggetto host [[HasProperty]] e memorizzano valori di proprietà, ma [[HasProperty]] genera sempre false .

(Non sono riuscito a trovare la verbiage equivalente nelle specifiche ES2015, ma è inevitabile che sia ancora così.) Di nuovo, al momento della stesura degli oggetti comuni come gli array nei browser moderni [istanze di NodeList , per esempio] fanno gestire [[HasProperty]] correttamente, ma è importante testare.)


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

ECMAScript5 (la versione su Javascript) per lavorare con gli array.

forEach : consente di scorrere tutti gli elementi dell'array e fare tutto ciò che è necessario con ciascun elemento.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is the #" + (index+1) + " in 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 su array utilizzando alcune funzionalità integrate.

map - Crea una nuova matrice 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']

riduci - Come dice il nome, riduce la matrice a un singolo valore chiamando la funzione data passando nell'elemento currenct 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

filter - Molto simile a tutti tranne che al filtro restituisce una matrice con gli elementi che restituiscono true alla funzione data.

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

// Output: [2,4,6]

Spero che questo sia utile.


La sintassi lambda normalmente non funziona in IE 10 o sotto.

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


If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters

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

Questo è un iteratore per l'elenco NON-sparse in cui l'indice inizia da 0, che è lo scenario tipico quando si ha a che fare con 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 # 2

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

Ogni tag p ottiene class="blue"

Esempio # 3

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

Ogni altro tag p ottiene class="red">

Esempio # 4

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

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

Attenzione quando si usa la stringa come funzione: la funzione viene creata fuori contesto e dovrebbe essere utilizzata solo quando si è certi dell'ambito della variabile. In caso contrario, è meglio passare le funzioni in cui l'ambito è più intuitivo.


Vorrei anche aggiungere questo come una composizione di un ciclo inverso e una risposta sopra per qualcuno che gradirebbe 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 come non sarà necessario dichiararlo in seguito con un'altra linea. È utile quando si esegue il ciclo 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, lo renderebbe un po 'più difficile da leggere. Inoltre, a seconda del browser, può essere "non" ottimizzato per funzionare più velocemente di quello originale.


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

per - è il più comune. Pieno blocco di codice per il loop

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 - passa anche attraverso 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 usato 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 sugli array, guarda il post del blog . Programmazione funzionale in JavaScript: mappare, filtrare e ridurre .


Non c'è alcun for eachciclo nel JavaScript nativo . È possibile utilizzare le librerie per ottenere questa funzionalità (io consiglio Underscore.js ), utilizzare un forciclo semplice .

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

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

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

Probabilmente il for(i = 0; i < array.length; i++)ciclo 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à riferimento a variabili che non hai nemmeno, in secondo luogo non avresti le variabili nell'array, e terzo questo 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
//!!!

Se si dispone di un enorme array, è necessario utilizzarlo iteratorsper guadagnare un po 'di efficienza. Gli iteratori sono una proprietà di alcune collezioni JavaScript (come Map, Set, String, Array). Anche, for...ofusa iteratorsotto il cofano.

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

Si accede all'elemento corrente chiamando il nextmetodo dell'iteratore . Il metodo successivo restituirà l' valueelemento 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 un values()metodo come questo:

    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 normale array in iterator 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 regolare arrayin un iteratorssimile:

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 inesauribile.
  • Gli oggetti non sono iterabledi default. Da usare for..inin quel caso perché al posto dei valori funziona con le chiavi.

Puoi leggere di più iteration protocol here .


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

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

Un altro modo percorribile sarebbe utilizzare ciò Array.map()che funziona allo stesso modo ma anche mutatesogni elemento e lo restituisce come:

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

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

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

Un esempio CodePen di come funziona è:

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

Guarda anche

  • Array::forEach .
  • In for_each...in (MDN) viene spiegato che for each (variable in object)è deprecato come parte dello standard ECMA-357 ( EAX ).
  • for...of (MDN) descrive il prossimo modo di iterare usando for (variable of object)come parte della proposta di Harmony (ECMAScript 6).

var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
    console.log("Index" + index);
    console.log("Element" + item);
})






iteration