Array.prototype.forEach()

Il metodo forEach() esegue una funzione che gli viene provvista per ogni elemento in un array.

var a = ['a', 'b', 'c'];

a.forEach(function(element) {
    console.log(element);
});

// a
// b
// c

Sintassi

arr.forEach(function callback(valoreCorrente, indice, array) {
    //il tuo iteratore
}[, thisArg]);

Parametri

callback
Funzione da eseguire per ogni elemento, prende tre argomenti:
valoreCorrente
Il valore corrente dell'elemento che viene processato nell'array.
indice
L'indice dell'elemento corrente che viene processato nell'array.
array
L'array a cui il forEach() è applicato.
thisArg Optional
Valore da utilizzare come this (i.e riferimento Object) quando viene eseguita la callback.

Valore di return

undefined.

Descrizione

forEach() esegue la callback una volta per ogni elemento presente nell'array in ordine ascendente. Non è invocato per proprietà dell'indice che sono state cancellate o non inizializzate (i.e. su array sparse).

callback è invocata con tre argomenti:

  • il valore dell'elemento
  • l'indice dell'elemento
  • l'array che viene attraversato

Se un argomento thisArg è fornito al forEach(), sarà utilizzato come valore this della callback. Altrimenti, il valore undefined sarà usato per this. Il valore this è osservabile dalla callback è determinato tramite le solite regole che determinano il this visto da una funzione.

L'intervallo di elementi processati da forEach() è impostato precedentemente alla prima invocazione della callback. Elementi che sono accodati all'array dopo la chiamata a forEach()  non sono visitati dalla callback. Se i valori degli elementi esistenti dell'array vengono cambiati, il valore passato alla callback sarà il valore al momento della chiamata di forEach(); gli elementi che sono stati cancellati prima della visita non verranno toccati dalla callback. Se gli elementi che sono già stati visitati vengono rimossi (e.g. utilizzando shift()) durante l'iterazione, gli elementi successivi saranno saltati - vedi l'esempio sotto.

forEach() esegue una callback per ogni elemento dell'array; diversamente da map()reduce() restituisce sempre il valore undefined e non è concatenabile. L'utilizzo tipico è di eseguire gli effetti secondari al termine di una concatenazione.

Non c'è modo di fermare o interrompere bruscamente un loop forEach() se non chiamando un exception. Se hai bisogno di un comportamento di questo tipo la soluzione ideale sarebbe utilizzare un normale loop e non un forEach(). Se stai testando gli elementi di un array per un predicato e hai bisogno di un valore di ritorno di tipo Booleano, puoi usare every()some(). Se disponibili, i nuovi metodi find()findIndex() possono essere utilizzati con interruzioni con dei predicati true.

Esempi

Stampare i contenuti di un array

Il codice seguente stampa una linea per ogni elemento di un array:

function logArrayElements(element, index, array) {
  console.log('a[' + index + '] = ' + element);
}

// Nota come l'indice 2 è saltato perchè non c'è nessun
// elemento in quella posizione
[2, 5, , 9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[1] = 5
// a[3] = 9

Utilizzare thisArg

Il prossimo esempio aggiorna le proprietà di un oggetto per ogni entrata nell'array:

function Counter() {
  this.sum = 0;
  this.count = 0;
}
Counter.prototype.add = function(array) {
  array.forEach(function(entry) {
    this.sum += entry;
    ++this.count;
  }, this);
  // ^---- Nota
};

var obj = new Counter();
obj.add([2, 5, 9]);
obj.count
// 3 
obj.sum
// 16

Il parametro thisArg (this) è fornito a forEach(), passato alla callback ogni volta che viene invocato per essere utilizzato come valore this.

Se si passa il parametro della funzione con un'espressione a freccia, il parametro thisArg può essere omesso in quanto le funzioni a freccia lessicalmente legano this.

Una funzione copia oggetto

Il codice seguente crea una copia di un dato oggetto. Ci sono differenze nelle modalità di creazione di copia di un oggetto, il seguente è uno dei tanti modi ed è presentato per spiegare come Array.prototype.forEach() funzioni utilizzando le meta proprietà delle funzioni ECMAScript 5 Object.*

function copy(obj) {
  var copy = Object.create(Object.getPrototypeOf(obj));
  var propNames = Object.getOwnPropertyNames(obj);

  propNames.forEach(function(name) {
    var desc = Object.getOwnPropertyDescriptor(obj, name);
    Object.defineProperty(copy, name, desc);
  });

  return copy;
}

var obj1 = { a: 1, b: 2 };
var obj2 = copy(obj1); // obj2 ora è come obj1

Se l'array è modificato durante l'iterazione, gli altri elementi potrebbero essere saltati.

L'esempio seguente stampa "one", "two", "four". Quando l'entrata contenente il valore "two" è raggiunta, la prima entrata dell'intero array è rimossa, con il risultato che il resto degli elementi dell'array cambiano di posizione. A causa di ciò l'elemento "four" ora è in una posizione precedente dell'array e "three" viene saltato. forEach() non fa copie dell'array prima dell'iterazione.

var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
  console.log(word);
  if (word === 'two') {
    words.shift();
  }
});
// one
// two
// four

Polyfill

forEach() è stato aggiunto allo standard ECMA-262 della quinta edizione; a causa di ciò potrebbe non essere presente in alcune implementazioni dello standard. Puoi aggirare il problema inserendo il codice seguente all'inizio dei tuoi script, permettendo successivamente l'utilizzo di forEach() in implementazioni che non lo supportano nativamente. L'algoritmo è esattamente quello specificato in ECMA-262, quinta edizione, assumento che ObjectTypeError abbiano i loro valori originali e callback.call() venga valutata al valore originale di Function.prototype.call().

// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {

  Array.prototype.forEach = function(callback/*, thisArg*/) {

    var T, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    // 1. Let O be the result of calling toObject() passing the
    // |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get() internal
    // method of O with the argument "length".
    // 3. Let len be toUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If isCallable(callback) is false, throw a TypeError exception. 
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. If thisArg was supplied, let T be thisArg; else let
    // T be undefined.
    if (arguments.length > 1) {
      T = arguments[1];
    }

    // 6. Let k be 0
    k = 0;

    // 7. Repeat, while k < len
    while (k < len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //    This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty
      //    internal method of O with argument Pk.
      //    This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Call the Call internal method of callback with T as
        // the this value and argument list containing kValue, k, and O.
        callback.call(T, kValue, k, O);
      }
      // d. Increase k by 1.
      k++;
    }
    // 8. return undefined
  };
}

Specificazioni

Specification Status Comment
ECMAScript 5.1 (ECMA-262)
The definition of 'Array.prototype.forEach' in that specification.
Standard Initial definition. Implemented in JavaScript 1.6.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Array.prototype.forEach' in that specification.
Standard  
ECMAScript Latest Draft (ECMA-262)
The definition of 'Array.prototype.forEach' in that specification.
Draft  

Compatibilità browser

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (Yes) 1.5 (1.8) 9 (Yes) (Yes)
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support (Yes) (Yes) 1.0 (1.8) (Yes) (Yes) (Yes)

Vedi anche

Tag del documento e collaboratori

 Hanno collaborato alla realizzazione di questa pagina: mnemosdev
 Ultima modifica di: mnemosdev,