Array.prototype.map()

Il metodo map() crea un nuovo array con i risultati della chiamata di una funzione fornita su ogni elemento dell'array chiamante.

Sintassi

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
    // Ritorna un elemento per new_array
}[, thisArg])

Parametri

callback
Funzione che produce un elemento del nuovo array, prendendo tre argomenti:
 
currentValue
L'elemento corrente in elaborazione nell'array.
indexOptional
L'indice dell'elemento corrente in elaborazione nell'array.
arrayOptional
L'array a cui viene applicato map.
thisArgOptional
Valore da utilizzare come this quando viene eseguito callback.

Valore di ritorno

Un nuovo array con ciascun elemento che è il risultato della funzione di callback.

Descrizione

map chiama il callback fornito una volta per ciascun elemento in un array, in ordine, e costruisce un nuovo array dai risultati. callback viene invocato solo per gli indici dell'array che hanno valori assegnati, incluso undefined. Non viene chiamato per gli elementi mancanti dell'array (ovvero, gli indici che non sono mai stati impostati, che sono stati cancellati o a cui non è mai stato assegnato un valore).

Poichè map costruisce un nuovo array, usarlo quando non si utilizza l'array restituito è un anti-pattern; usa forEachfor-of invece. Segni che non dovresti usare map: A) Non stai usando l'array restituito, e/o B) Non stai restituendo un valore dal callback.

callback viene invocato con tre argomenti: il valore dell'elemento, l'indice dell'elemento e l'oggetto Array che viene iterato.

Se viene fornito il parametro thisArg a map, 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.

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

L'intervallo di elementi elaborati da map viene impostato prima della prima chiamata del callback. Gli elementi aggiunti all'array dopo che la chiamata a map 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 map li visita. Gli elementi che vengono cancellati dopo che la chiamata a map inizia e prima di essere visitati non vengono visitati.

A causa dell'algoritmo definito nella specifica, se l'array su cui è stata chiamato map è sparso, l'array risultante sarà sparso, mantenendo vuoti gli stessi indici.

Esempi

Mappare una serie di numeri ad un array di radici quadrate

Il seguente codice accetta un array di numeri e crea un nuovo array contenente le radici quadrate dei numeri nel primo array.

var numbers = [1, 4, 9];
var roots = numbers.map(function(num) {
return Math.sqrt(num)
});
// roots è ora [1, 2, 3]
// numbers è ancora [1, 4, 9]

Usare map per riformattare gli oggetti in un array

Il seguente codice accetta un array di oggetti e crea un nuovo array contenente gli oggetti appena riformattati.

var kvArray = [{key: 1, value: 10}, 
               {key: 2, value: 20}, 
               {key: 3, value: 30}];

var reformattedArray = kvArray.map(obj =>{ 
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});
// reformattedArray è ora [{1: 10}, {2: 20}, {3: 30}], 

// kvArray è ancora:
// [{key: 1, value: 10}, 
//  {key: 2, value: 20}, 
//  {key: 3, value: 30}]

Mappare un array di numeri usando una funzione che contiene un argomento

Il codice seguente mostra come funziona map quando viene utilizzata una funzione che richiede un argomento. L'argomento verrà assegnato automaticamente da ciascun elemento dell'array mentre map itera l'array originale.

var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
  return num * 2;
});

// doubles is now [2, 8, 18]
// numbers is still [1, 4, 9]

Usare map genericamente

Questo esempio mostra come usare map su una String per ottenere un array di byte nella codifica ASCII che rappresenta i valori dei caratteri:

var a = Array.prototype.map.call('Hello World', function(x) { 
  return x.charCodeAt(0); 
});
// a ora equivale a [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

Usare map con querySelectorAll

Questo esempio mostra come iterare attraverso una raccolta di oggetti raccolti da querySelectorAll. Questo perchè querySelectorAll restituisce una NodeList che è una raccolta di oggetti.
In questo caso restituiamo sullo schermo tutti i valori delle opzioni selezionate:

var elems = document.querySelectorAll('select option:checked');
var values = Array.prototype.map.call(elems, function(obj) {
  return obj.value;
});

Il modo più semplice sarebbe utilizzare il metodo Array.from().

Caso d'uso ingannevole

(inspired by this blog post)

È normale utilizzare il callback con un argomento (l'elemento che viene attraversato). Alcune funzioni sono anche comunemente utilizzate con un argomento, anche se accettano argomenti opzionali aggiuntivi. Queste abitudini possono portare a comportamenti confusi.

// Consider:
['1', '2', '3'].map(parseInt);
// Mentre ci si potrebbe aspettare [1, 2, 3]
// Il risultato effettivo è [1, NaN, NaN]

// parseInt è spesso usato con un argomento, ma ne prende due.
// Il primo è un'espressione e il secondo è la radice.
// Alla funzione di callback, Array.prototype.map passa 3 argomenti:
// l'elemento, l'indice e l'array
// Il terzo argomento è ignorato da parseInt, ma non il secondo,
// da qui l'eventuale confusione. Vedi il post del blog per maggiori dettagli
// Se il link non funziona
// ecco un esempio conciso dei passaggi di iterazione:
// parseInt(string, radix) -> map(parseInt(value, index))
// first iteration (index is 0): parseInt('1', 0) // results in parseInt('1', 0) -> 1
// second iteration (index is 1): parseInt('2', 1) // results in parseInt('2', 1) -> NaN
// third iteration (index is 2): parseInt('3', 2) // results in parseInt('3', 2) -> NaN

function returnInt(element) {
  return parseInt(element, 10);
}

['1', '2', '3'].map(returnInt); // [1, 2, 3]
// Il risultato effettivo è un array di numeri (come previsto)

// Come sopra, ma usando la sintassi della funzione a freccia concisa
['1', '2', '3'].map( str => parseInt(str) );

// Un modo più semplice per ottenere quanto sopra, evitando il "gotcha":
['1', '2', '3'].map(Number); // [1, 2, 3]
// ma a differenza di `parseInt` restituirà anche una notazione esponenziale mobile o (risolta):
['1.1', '2.2e2', '3e300'].map(Number); // [1.1, 220, 3e+300]

Un output alternativo del metodo map che viene chiamato con parseInt come parametro viene eseguito come segue:

var xs = ['10', '10', '10'];

xs = xs.map(parseInt);

console.log(xs);
// Il risultato effettivo di 10,NaN,2 potrebbe essere inaspettato in base alla descrizione precedente.

Polyfill

map è stato aggiunto allo standard ECMA-262 nella 5a edizione; in quanto tale potrebbe non essere presente in tutte le implementazioni dello standard. Puoi aggirare questo problema inserendo il seguente codice all'inizio degli script, consentendo l'uso di map in implementazioni che non lo supportano in modo nativo. Questo algoritmo è esattamente quello specificato in ECMA-262, 5a edizione, assumendo Object, TypeError, e Array hanno i loro valori originali e che callback.call restituisce il valore originale di Function.prototype.call.

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

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

    var T, A, 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 A be a new array created as if by the expression new Array(len) 
    //    where Array is the standard built-in constructor with that name and 
    //    len is the value of len.
    A = new Array(len);

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

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

      var kValue, mappedValue;

      // 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. Let mappedValue be the result of calling the Call internal 
        //     method of callback with T as the this value and argument 
        //     list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor
        // { Value: mappedValue,
        //   Writable: true,
        //   Enumerable: true,
        //   Configurable: true },
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, k, {
        //   value: mappedValue,
        //   writable: true,
        //   enumerable: true,
        //   configurable: true
        // });

        // For best browser support, use the following:
        A[k] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };
}

Specifiche

Specifica Stato Commento
ECMAScript 5.1 (ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Standard Definizione iniziale Implementato in JavaScript 1.6.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Standard  
ECMAScript Latest Draft (ECMA-262)
The definition of 'Array.prototype.map' 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
mapChrome Full support YesEdge Full support 12Firefox Full support 1.5IE Full support 9Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes

Legend

Full support  
Full support

Vedi anche