Array.prototype.map()

Resum

El mètode map() crea una nova array amb els resultats de la crida a la funció proporcionada un cop per cada element.

Sintaxi

arr.map(callback[, thisArg])

Paràmetres

callback
Funció que produeix un element de la nova array, agafant tres arguments:
currentValue
El valor actual que és processat en l'array.
index
L'índex de l'element actual que és processat en l'array.
array
L'array sobre la qual es crida map.
thisArg
Opcional. Valor a usar com a this quan s'executa la funció.

Descripció

map crida a la funció passada callback un cop per cada element de l'array, en ordre, i construeix un nou array a partir dels resultats. Només s'invoca callback per a posicions de l'array que tinguin valors assignats, incloent undefined. No es crida per a elements no trobats (és a dir, elements que no han rebut mai un valor o bé elements que s'han eliminat).

S'invoca callback amb tres arguments: el valor de l'element, la posició de l'element a l'array, i l'array que s'està recorrent.

Si s'ha proporcionat el paràmetre thisArg a l'hora de cridar map, aquest es passarà a la funció callback com a valor per a this dins la funció. En qualsevol altre cas el valor utilitzat com a this serà undefined. El valor finalment observable des de callback es determinarà d'acord a les regles usuals per a determinar el valor de this dins una funció.

map no canvia l'array des del que es crida (tot i que callback, si s'invoca, pot fer-ho).

El rang d'elements processat per map s'estableix abans de la primera invocació de callback. Els elements que s'hagin afegit a l'array després d'haver cridat map no seran visitats per callback. Si es canvient els elements existents, o s'eliminen, el valor passat a callback serà el valor que tinguessin quan es va invocar map; els elements que s'han eliminat no es visitaran.

Exemples

Exemple: Generar un array de rels quadrades a partir d'un array de nombres

El codi següent agafa un array de nombres i crea un nou array que contindrà les rels quadrades dels nombres del primer array.

var nombres = [1, 4, 9];
var rels = nombres.map(Math.sqrt);
// rels ara val [1, 2, 3], nombres encara val [1, 4, 9]

Exemple: Utilitzar map per a canviar el format dels objectes d'un array

El codi següent agafa un array d'objectes i crea un nou array que conté els nous objectes, que tenen un format diferent.

var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){ 
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});
// reformattedArray ara val [{1:10}, {2:20}, {3:30}], 
// kvArray encara val [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}]

Exemple: Assignar els nombres d'un array al resultat d'una funció que espera un argument

El codi següent mostra com funciona map quan s'utilitza una funció que espera un argument. L'argument rebrà automàticament el valor de cada element de l'array mentre map recorre tot l'array original.

var nombres = [1, 4, 9];
var dobles = nombres.map(function(num) {
  return num * 2;
});
// dobles ara val [2, 8, 18]. nombres encara val [1, 4, 9]

Exemple: utilitzar map de forma genèrica

Aquest exemple mostra com utilitzar map en un String per a obtindre un array de bytes que representin el valor dels caràcters codificats amb ASCII:

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

Exemple: Utilitzar map de forma genèrica amb querySelectorAll

Aquest exemple mostra com iterar sobre una col·lecció d'objectes obtinguts mitjançant querySelectorAll. En aquest cas obtenim totes les opcions seleccionades de la web:

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

Exemple: Utilitzar map per a invertir un string

var str = '12345';
Array.prototype.map.call(str, function(x) {
  return x;
}).reverse().join(''); 

// Sortida: '54321'
// Bonus: utilitzeu '===' per a comprovar si l'string original era un palindrom

Exemple: Un cas d'ús delicat

(inspirat per aquesta entrada de blog)

És comú utilitzar la funció callback amb un sol argument (l'element corresponent a la volta del bucle de l'array que s'està recorrent). Algunes funcions també solen requerir un sol argument, tot i que també poden acceptar arguements adicionals de forma opcional. Això pot produïr comportaments confussos.

// Considerem:
['1', '2', '3'].map(parseInt);
// Quan hom esperaria [1, 2, 3]
// El resultat real serà [1, NaN, NaN]

// parseInt s'utilitza normalment amb un argument, però admet dos.
// El primer és una expressió mentre que el segon és el mòdul.
// Array.prototype.map passa 3 arguments a la funció callback: 
// l'element, la posició de l'element i l'array
// parseInt ignorarà el tercer argument, però no el segon,
// provocant la confussió. Vegeu l'entrada del blog per a més detalls

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

['1', '2', '3'].map(returnInt); // [1, 2, 3]
// Actual result is an array of numbers (as expected)

// A simpler way to achieve the above, while avoiding the "gotcha":
['1', '2', '3'].map(Number); // [1, 2, 3]

Polyfill

map va ser afegit a l'standard ECMA-262 a la cinquena edició; degut a això aquest pot no estar present en algunes implementacions de l'standard. Es pot solventar aquest problema insertant el codi següent al principi dels scripts que el requereixin, permetent que implementacions on map no està disponible de forma nativa en puguin fer ús. Aquest algoritme és exactament l'especificat per l'ECMA-262, 5a edició, assument que Object, TypeError, i Array tenen els seus valors originals i que callback.call s'evalua al valor original de 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. Assignem a O el resultat de cridar a ToObject passant-li el valor de |this| 
    //    com a argument.
    var O = Object(this);

    // 2. lenValue és el resultat de cridar el mètode intern
    //    Get de O amb l'argument "length".
    // 3. Assignem a len el valor d'executar ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. Si IsCallable(callback) és false, llencem l'excepció TypeError.
    // Vegeu: http://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. Si s'ha passat l'argument thisArg, l'assigment a T; en cas contrari T valdrà undefined.
    if (arguments.length > 1) {
      T = thisArg;
    }

    // 6. Assignem a A el nou array creat per l'expressió new Array(len) 
    //    on Array és el constructor standard de JavaScript amb aquest nom i
    //    len és el valor de len.
    A = new Array(len);

    // 7. Assignem 0 a k
    k = 0;

    // 8. Repetim mentre k < len
    while (k < len) {

      var kValue, mappedValue;

      // a. Assignem ToString(k) a Pk.
      //   Això és implicit per a operands al cantó esquerra de l'operador in
      // b. Assignem a kPresent el resultat de cridar el mètode intern HasProperty
      //    de O amb l'argument Pk.
      //   Es pot combinar aquest pas amb c
      // c. Si kPresent és true, llavors
      if (k in O) {

        // i. Assignem a kValue el resultat de cridar el mètode intern
        //    Get de O amb l'argument Pk.
        kValue = O[k];

        // ii. Assignem a mappedValue el resultat de cridar el mètode intern Call
        //     de callback amb T com a valor de this i una llista d'arguments
        //     que conté kValue, k, i O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Cridem el mètode intern DefineOwnProperty de A amb els arguments
        // Pk, Property Descriptor
        // { Value: mappedValue,
        //   Writable: true,
        //   Enumerable: true,
        //   Configurable: true },
        // i false.

        // En navegadors que suportin Object.defineProperty, utilitzeu el següent:
        // Object.defineProperty(A, k, {
        //   value: mappedValue,
        //   writable: true,
        //   enumerable: true,
        //   configurable: true
        // });

        // Per a un millor suport de navegadors, utilitzeu el següent:
        A[k] = mappedValue;
      }
      // d. incrementem k en 1.
      k++;
    }

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

Especificacions

Especificació Estat Comentaris
ECMAScript 5.1 (ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Standard Definició inicial. Implementat a JavaScript 1.6.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Array.prototype.map' in that specification.
Standard  

Compatibilitat amb navegadors

Característica Chrome Firefox (Gecko) Internet Explorer Opera Safari
Suport bàsic (Yes) 1.5 (1.8) 9 (Yes) (Yes)
Característica Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Suport bàsic (Yes) (Yes) 1.0 (1.8) (Yes) (Yes) (Yes)

Vegeu també

Document Tags and Contributors

 Contributors to this page: dsabalete, enTropy, llue
 Last updated by: dsabalete,