Array.prototype.forEach()

Il metodo forEach() esegue una funzione fornita una volta per ogni elemento dell'array.

Sintassi

arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);

Parametri

callback
Funzione da eseguire per ciascun elemento, prendendo tre argomenti:
currentValue
L'elemento corrente in elaborazione nell'array.
index Optional
L'indice dell'elemento corrente in elaborazione nell'array.
array Optional
L'array a cui viene applicato forEach().
thisArg Optional
Valore da utilizzare come this quando si esegue callback.

Descrizione

forEach() esegue il callback fornito una volta per ciascun elemento presente nell'array in ordine crescente. Non è invocato per le proprietà dell'indice che sono state eliminate o non inizializzate (ad esempio su array sparsi).

callback viene invocato con tre argomenti:

  • il valore dell'elemento
  • l'indice dell'elemento
  • l'array che deve essere iterato

Se viene fornito il parametro thisArg a forEach(), verrà utilizzato come valore this del callback. Altrimenti, il valore undefined sarà usato come valore this. Il valore this alla fine osservabile da callback è determinato secondo le consuete regole per determinare il this visto da una funzione.

L'intervallo di elementi elaborati da forEach() viene impostato prima della prima chiamata del callback. Gli elementi aggiunti all'array dopo che la chiamata forEach() inizia non saranno calcolati da callback. Se i valori degli elementi esistenti dell'array vengono modificati, il valore passato a callback sarà il valore al momento in cui forEach() li visita; gli elementi che vengono cancellati prima di essere visitati non vengono visitati. Se gli elementi già visitati vengono rimossi (ad esempio usando shift()) durante l'iterazione, gli elementi successivi verranno saltati - vedi l'esempio sotto.

forEach() esegue la funzione callback una volta per ogni elemento dell'array; a differenza di map()reduce() restituisce sempre undefined e non è concatenabile. Il tipico caso d'uso è eseguire effetti collaterali alla fine del chain.

forEach() non muta l'array su cui è chiamato (sebbene callback, se invocato, possa farlo).

Non c'è modo di fermare o interrompere un loop forEach() se non lanciando un'eccezione. Se hai bisogno di un simile comportamento, il metodo forEach() è lo strumento sbagliato.

La risoluzione anticipata può essere eseguita con:

Gli altri metodi per array: Array.prototype.every()Array.prototype.some()Array.prototype.find(), e Array.prototype.findIndex() testano gli elementi dell'array con un predicato restituendo un valore di verità per determinare se è necessaria un'ulteriore iterazione.

Esempi

Convertire un loop for in forEach

const items = ['item1', 'item2', 'item3'];
const copy = [];

// prima
for (let i=0; i<items.length; i++) {
  copy.push(items[i]);
}

// dopo
items.forEach(function(item) {
  copy.push(item);
});

Stampa del contenuto di un array

Note: Per visualizzare il contenuto di un array nella console, puoi utilizzare console.table() che stamperà una versione formattata dell'array. L'esempio seguente illustra un altro modo per farlo, usando forEach().

Il seguente codice logga una linea per ogni elemento in un array:

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

// Nota che l'indice 2 viene saltato poiché non vi è alcun elemento
// in quella posizione nell'array.
[2, 5, , 9].forEach(logArrayElements);
// logga:
// a[0] = 2
// a[1] = 5
// a[3] = 9

Usare thisArg

Il seguente esempio (inventato) aggiorna le proprietà di un oggetto da ciascuna voce dell'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
};

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

Poiché il parametro thisArg (this) viene fornito a forEach(), viene passato a callback ogni volta che viene richiamato, per essere utilizzato come valore this.

Se si passa l'argomento della funzione utilizzando un'espressione della funzione a freccia il parametro thisArg può essere omesso poiché le funzioni a freccia associano in modo lessicale il valore this.

Una funzione di copia di oggetti

Il seguente codice crea una copia di un dato oggetto. Esistono diversi modi per creare una copia di un oggetto; il seguente è solo un modo e viene presentato per spiegare come funziona Array.prototype.forEach() usando le funzioni di meta proprietà ECMAScript 5 Object.*.

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

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

  return copy;
}

const obj1 = { a: 1, b: 2 };
const obj2 = copy(obj1); // obj2 looks like obj1 now

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

L'esempio seguente registra "uno", "due", "quattro". Quando viene raggiunta la voce contenente il valore "due", la prima voce dell'intero array viene spostata, il che comporta il trasferimento di tutte le voci rimanenti in una posizione. Poiché l'elemento "quattro" è ora in una posizione precedente nell'array, "tre" verrà saltato. forEach() non esegue una copia dell'array prima di iterare.

var words = ['uno', 'due', 'tre', 'quattro'];
words.forEach(function(word) {
  console.log(word);
  if (word === 'due') {
    words.shift();
  }
});
// uno
// due
// quattro

Appiattire un array

Il seguente esempio è qui solo per scopi didattici. Se si desidera appiattire un array usando metodi built-in, è possibile utilizzare Array.prototype.flat() (che dovrebbe essere parte di ES2019 e già implementato in alcuni browser).

/**
 * Flattens ha passato un array in un array dimensionale
 *
 * @params {array} arr
 * @returns {array}
 */
function flatten(arr) {
  const result = []

  arr.forEach((i) => {
    if (Array.isArray(i)) {
      result.push(...flatten(i))
    } else {
      result.push(i)
    }
  })
  
  return result
}

// Uso
const problem = [1, 2, 3, [4, 5, [6, 7], 8, 9]]

flatten(problem) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

Polyfill

forEach() è stato aggiunto allo standard ECMA-262 nella quinta edizione; in quanto tale potrebbe non essere presente in altre implementazioni dello standard. È possibile aggirare questo problema inserendo il seguente codice all'inizio degli script, consentendo l'uso di forEach() nelle implementazioni che non lo supportano in modo nativo. Questo algoritmo è esattamente quello specificato in ECMA-262, 5a edizione, assumendo Object e TypeError hanno i loro valori originali e quel callback.call() valuta il 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.
  };
}

Specifiche

Specifica Stato Commento
ECMAScript 5.1 (ECMA-262)
The definition of 'Array.prototype.forEach' in that specification.
Standard Definizione iniziale Implementato 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à con i browser

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
forEachChrome Full support 1Edge Full support 12Firefox Full support 1.5IE Full support 9Opera Full support YesSafari Full support YesWebView Android Full support ≤37Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes

Legend

Full support  
Full support

Vedi anche