mozilla

Array.prototype.map()

Résumé

La méthode map() crée un nouveau tableau composé des images des éléments d'un tableau par une fonction donnée en argument.

Syntaxe

arr.map(callback[, thisArg])

Paramètres

callback
La fonction qui est utilisée pour créer un élément du nouveau tableau. Elle utilise trois arguments :
valeurCourante
La valeur de l'élément du tableau à traiter.
index
L'index de l'élément qui est traité par la fonction.
tableau
Le tableau sur lequel on a appelé la méthode map.
thisArg
Paramètre optionnel. La valeur à utiliser pour this lors de l'exécution de callback.

Description

Lorsqu'on utilise map, la fonction callback fournie en argument est exécutée une fois pour chacun des éléments du tableau, dans l'ordre du tableau. Chaque résultat de l'opération sur un élément sera un élément du nouveau tableau. La fonction callback est appelée uniquement pour les indices du tableau pour lesquels il y a des valeurs affectées. Si les valeurs ont été supprimées ou qu'elles n'ont jamais été initialisées, la fonction ne sera pas appelée.

callback est appelé avec trois arguments : la valeur de l'élément du tableau, l'index de cet élément, l'objet Array qui est parcouru.

Si le paramètre thisArg est utilisé, il sera utilisé en tant que this par la fonction callback lorsqu'elle sera appelée. S'il n'est pas utilisé, ce sera la valeur undefined qui sera utilisée pour définir this. La valeur this finalement prise en compte par la fonction callback est définie selon les règles usuelles qui déterminent la valeur this observée par une fonction.

map ne modifie pas le tableau sur lequel elle est appelée (bien que la fonction callback, si elle est appelée, puisse modifier le tableau).

La liste des éléments à traiter lors de l'opération map est définie avant le premier appel à callback. Les éléments qui sont ajoutés au tableau après que l'appel à map ait été initié ne seront pas traités par la fonction callback. Si des éléments ont été modifiés, la valeur utilisée par la fonction callback sera celle au moment où map est utilisée. Les éléments qui sont supprimés ne sont pas traités.

Exemples

Créer un tableau des racines carrées d'un tableau de nombre

Dans l'exemple suivant, on crée un tableau composé des racines carrées des éléments d'un premier tableau :

var nombres = [1, 4, 9];
var racines = nombres.map(Math.sqrt);
// racines vaut désormais [1, 2, 3], nombres vaut toujours [1, 4, 9]

Créer un tableau de nombres avec une fonction à un argument

Ici, on illustre le fonctionnement de map avec une fonction à un argument. Cet argument sera automatiquement remplacé par chaque élément du tableau au fur et à mesure que map parcourt le tableau :

var nombres = [1, 4, 9];
var doubles = nombres.map(function(num) {
  return num * 2;
});
// doubles vaut désormais [2, 8, 18]. nombres vaut toujours [1, 4, 9]

Using map pour changer le format d'objets dans un tableau

Dans le code qui suit, on utilise un tableau d'objets pour créer un autre tableau contenant de nouveaux objets dans un autre format :

var tableauOrig = [{clé:1, valeur:10}, {clé:2, valeur:20}, {clé:3, valeur: 30}];
var tableauFormaté = tableauOrig.map(function(obj){ 
  var rObj = {};
  rObj[obj.clé] = obj.valeur; 
  return rObj;
});
// tableauFormaté vaut maintenant [{1:10}, {2:20}, {3:30}], 
// tableauOrig vaut toujours [{clé:1, valeur:10}, {clé:2, valeur:20}, {clé:3, valeur: 30}]

Utiliser map de façon générique

Dans cet exemple, on voit comment utiliser la fonction map sur une chaîne de caractères pour obtenir un tableau contenant les codes ASCII des valeurs encodées :

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

Utiliser map avec querySelectorAll

Dans cet exemple, on illustre comment utiliser la méthode map de façon générique, sur un tableau d'objets collectés grâce à querySelectorAll :

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

Utiliser map pour inverser une chaîne de caractères

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

// Résultat : '54321'
// Bonus : On peut ensuite utiliser '===' pour tester si la chaîne est un palindrome

Un résultat inattendu

Exemple inspiré par ce billet (en anglais)

Il est fréquent d'utiliser la fonction callback avec un seul argument (l'élément en cours). Certaines fonctions natives sont également souvent appelées avec un unique argument même si elles peuvent prendre en compte plusieurs arguments. En combinant ces deux « habitudes », on peut obtenir certains résultats inattendus :

// Si on utilise :
['1', '2', '3'].map(parseInt);
// On s'attend à obtenir [1, 2, 3]
// Le résultat qu'on obtient est en fait [1, NaN, NaN]

// parseInt est souvent utilisé avec un argument mais il 
// peut être utilisé avec deux arguments
// Le premier correspond à l'expression à parser et le second
// à la base dans laquelle convertir
// Array.prototype.map passe 3 arguments à callback : 
// l'élément, l'index et le tableau
// Le troisième argument sera ignoré par parseInt mais pas le
// deuxième, ce qui donnera ce résultat étrange

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

['1', '2', '3'].map(returnInt); // [1, 2, 3]
// Le résultat qu'on obtient avec la fonction auxiliaire

// Une autre méthode, plus simple
['1', '2', '3'].map(Number); // [1, 2, 3]

Prothèse d'émulation (polyfill)

map a été ajouté avec la cinquième édition du standard ECMA-262 (ECMAScript). Pour cette raison, il se peut que certains navigateurs ne disposent pas encore de cette fonctionnalité. Malgré tout, il est possible d'émuler son comportement avec du code JavaScript. Le code suivant vous permet donc d'implémenter la fonctionnalité au sein de vos scripts afin de pouvoir utiliser map dans les environnements qui n'en disposent pas nativement. L'algorithme utilisé ici est exactement celui défini par ECMAScript 5 si on a bien Object, TypeError, et Array qui ont leurs valeurs originelles et que callback.call est bien évalué avec la valeur originelle de Function.prototype.call.

// Production steps / ECMA-262, Edition 5, 15.4.4.19
// Référence : 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 est null ou non défini');
    }

    // 1. Soit O le résultat de l'appel ToObject avec |this| 
    //    comme argument.
    var O = Object(this);

    // 2. Soit lenValue le résultat de l'appel de la méthode interne
    //    Get de O avec l'argument "length".
    // 3. Soit len égal à ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. Si IsCallable(callback) vaut false, on renvoie une TypeError
    // Voir : http://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' n est pas une fonction');
    }

    // 5. Si thisArg a été utilisé, on définit T avec thisArg
    //    sinon T vaudra undefined.
    if (arguments.length > 1) {
      T = thisArg;
    }

    // 6. Soit A un nouveau tableau créé tel
    //    qu'avec l'expression new Array(len) 
    //    où Array est le constructeur natif standard
    A = new Array(len);

    // 7. Soit k égal à 0
    k = 0;

    // 8. On répète tant que k < len
    while (k < len) {

      var kValue, mappedValue;

      // a. Soit Pk égal à ToString(k).
      //    (implicite pour l'opérande gauche de in)
      // b. Soit kPresent le résultat de l'appel à la méthode
      //    interne de O HasProperty appelée avec l'argument 
      //     Pk.
      //    Cette étape peut être combinée avec c
      // c. Si kPresent vaut true, alors
      if (k in O) {

        // i. Soit kValue le résultat de l'appel de la méthode
        //    interne Get de O avec l'argument Pk.
        kValue = O[k];

        // ii. Soit mappedValue le résultat de l'appel de la 
        //     méthode interne Call de callback avec T comme première
        //     valeur et la liste des arguments kValue, k, et O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. On appelle la méthode intnerne DefineOwnProperty de A
        // avec les arguments Pk, Property Descriptor
        // { Value: mappedValue,
        //   Writable: true,
        //   Enumerable: true,
        //   Configurable: true },
        // et false.

        // Pour les navigateurs qui supportent Object.defineProperty
        // on pourra utiliser :
        // Object.defineProperty(A, k, {
        //   value: mappedValue,
        //   writable: true,
        //   enumerable: true,
        //   configurable: true
        // });

        // Pour un meilleur suppport, on utilisera :
        A[k] = mappedValue;
      }
      // d. On augmente k de 1.
      k++;
    }

    // 9. On renvoie A
    return A;
  };
}

Spécifications

Spécification Statut Commentaires
ECMAScript 5.1 (ECMA-262)
La définition de 'Array.prototype.map' dans cette spécification.
Standard Définition initiale. Implémentée avec JavaScript 1.6.
ECMAScript 6 (ECMA-262)
La définition de 'Array.prototype.map' dans cette spécification.
Projet  

Compatibilité des navigateurs

Fonctionnalité Chrome Firefox (Gecko) Internet Explorer Opera Safari
Support simple (Oui) 1.5 (1.8) 9 (Oui) (Oui)
Fonctionnalité Android Chrome pour Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Support simple (Oui) (Oui) 1.0 (1.8) (Oui) (Oui) (Oui)

Voir aussi

Étiquettes et contributeurs liés au document

Contributeurs à cette page : teoli, BenoitL, Mgjbot, SphinxKnight, shitsod, ZeSeb, nielk
Dernière mise à jour par : SphinxKnight,
Masquer la barre latérale