243 votes

Comment convertir un objet simple en une carte ES6 ?

Pour une raison quelconque, je n'arrive pas à trouver cette simple chose dans la section Documents MDN (peut-être que je ne le vois pas).

Je m'attendais à ce que ça marche :

const map = new Map({foo: 'bar'});

map.get('foo'); // 'bar'

...mais la première ligne jette TypeError: (var)[Symbol.iterator] is not a function

Comment faire une carte à partir d'un simple objet ? Dois-je vraiment commencer par le convertir en un tableau de tableaux de paires clé-valeur ?

4 votes

Pour info, il peut être intéressant de changer votre réponse acceptée de mine a nils' o de bergers . Object.entries est vraiment la meilleure approche par rapport à Object.keys et l'approche de la fonction de générateur de bergi est légèrement plus directe que l'une ou l'autre de ces approches. Object.keys o Object.entries .

357voto

nils Points 11708

Oui, le Map prend un tableau de paires clé-valeur.

Object.entries est une nouvelle méthode statique Object disponible dans ES2017 (19.1.2.5) .

const map = new Map(Object.entries({foo: 'bar'}));

map.get('foo'); // 'bar'

Elle est actuellement mise en œuvre dans Firefox 46+ et Edge 14+ et dans les versions plus récentes de Chrome.

Si vous devez prendre en charge des environnements plus anciens et que la transpilation n'est pas une option pour vous, utilisez un polyfill, tel que celui recommandé par georg :

Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);

4 votes

Un "polyfill" sera plutôt trivial : Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])

0 votes

Concernant ton commentaire à la fin, je pense que s'ils utilisent const ils sont en train de transposer. :-)

0 votes

@T.J.Crowder c'est probablement vrai :) je ne suis pas sûr qu'ils transposent seulement ES2015 cependant.

75voto

T.J. Crowder Points 285826

Veuillez consulter réponse de nils utilisant Object.entries et/ou réponse de bergi utilisant une fonction générateur . Bien que Object.entries n'était pas encore dans les spécifications lorsque la question a été posée, il était au stade 4 donc sans danger pour le remplissage et l'utilisation, même en avril 2016 (tout juste). (Plus d'informations sur les étapes aquí .) Et les fonctions de générateur étaient dans ES2015. L'OP a spécifiquement demandé d'éviter les intermédiaires, et bien que le générateur ne l'évite pas complètement, il fait un meilleur travail que le générateur ci-dessous ou (légèrement) le générateur ES2015. Object.enties .

Pour info, en utilisant Object.entries :

  • Crée un tableau de [name, value] tableaux à passer à new Map
  • El Map Le constructeur appelle une fonction sur le tableau pour obtenir un itérateur ; le tableau crée et renvoie un objet interacteur de tableau.
  • El Map utilise cet objet itérateur pour récupérer les entrées (l'objet [name, value] ) et construire la carte

Utilisation du générateur :

  • Crée un objet générateur à la suite de l'appel de la fonction générateur.
  • El Map appelle une fonction sur cet objet générateur pour obtenir un itérateur à partir de celui-ci ; l'objet générateur renvoie la fonction lui-même
  • El Map utilise l'objet générateur (comme un itérateur) pour obtenir les entrées (l'objet [name, value] ) et construire la carte

Donc : Un intermédiaire de moins (le tableau de Object.entries ).

Cependant, l'utilisation de Object.entries est plus simple et la création de ce tableau n'est pas un problème dans 99,999 % des cas. Donc, vraiment, l'un ou l'autre. Mais ils sont tous les deux meilleurs que ceux ci-dessous. :-)


Réponse originale :

Pour initialiser un Map Vous pouvez utiliser n'importe quel itérateur qui renvoie des paires clé/valeur sous forme de tableaux, par exemple un tableau de tableaux :

const map = new Map([
    ['foo', 'bar']
]);

Il n'y a pas de conversion intégrée d'un objet à une carte, mais on peut facilement le faire avec la fonction Object.keys :

const map = new Map();
let obj = {foo: 'bar'};
Object.keys(obj).forEach(key => {
    map.set(key, obj[key]);
});

Vous pouvez, bien sûr, vous doter d'une fonction de travailleur pour gérer cela :

function buildMap(obj) {
    let map = new Map();
    Object.keys(obj).forEach(key => {
        map.set(key, obj[key]);
    });
    return map;
}

Puis

const map = buildMap({foo: 'bar'});

Ou voici une version plus l33t (c'est encore un truc ?) :

function buildMap(obj) {
    return Object.keys(obj).reduce((map, key) => map.set(key, obj[key]), new Map());
}

(Oui, Map#set renvoie la référence de la carte. Certains diront que c'est une abus de pouvoir de reduce .)

Ou nous pouvons realmente faire l'impasse sur l'obscurité :

const buildMap = o => Object.keys(o).reduce((m, k) => m.set(k, o[k]), new Map());

Non, je ne ferais jamais ça pour de vrai. :-)

37voto

Bergi Points 104242

Dois-je vraiment commencer par le convertir en un tableau de tableaux de paires clé-valeur ?

Non, un itérateur de tableaux de paires clé-valeur est suffisant. Vous pouvez utiliser ce qui suit pour éviter de créer le tableau intermédiaire :

function* entries(obj) {
    for (let key in obj)
        yield [key, obj[key]];
}

const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'

0 votes

Bel exemple - juste une note pour les autres, vous pourriez vouloir faire un if(!obj.hasOwnProperties(key)) continue; juste après la condition de la boucle for pour s'assurer que vous ne céderez pas les propriétés héritées du prototype de l'objet (à moins que vous ne fassiez confiance à l'objet, mais vous devriez le faire de toute façon lorsque vous itérez des objets à l'aide de la méthode in comme une bonne habitude).

6 votes

@Puiu Non, vous ne devriez pas, et c'est une mauvaise habitude. Si vous ne faites pas confiance à l'objet, vous ne devez pas faire confiance à son .hasOwnProperty également, et vous devrez utiliser la propriété Object.prototype.hasOwnProperty.call(obj, key)

0 votes

@Bergi c'est un bon point, il se pourrait que l'objet de l'objet hasOwnProperty a également été écrasé. Vous voulez dire que c'est une bonne pratique de ne pas s'embêter à vérifier ? Simple curiosité, toutes les conventions qui existent disent de vérifier ou suggèrent d'éviter d'utiliser for...in de toute façon. J'aimerais connaître votre avis sur la question.

27voto

Andrew Willems Points 5352

La réponse de Nils décrit comment pour convertir les objets en cartes, ce que j'ai trouvé très utile. Cependant, le PO se demandait également où se trouvaient ces informations dans la documentation du MDN. Bien qu'elle n'ait pas été présente au moment où la question a été posée, elle se trouve désormais sur la page MDN consacrée à la conversion des objets en cartes. Objet.entries() sous l'intitulé Convertir un objet en carte qui stipule :

Convertir un objet en carte

El new Map() accepte un itérable de entries . Avec Object.entries vous pouvez facilement convertir de Object a Map :

const obj = { foo: 'bar', baz: 42 }; 
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

8voto

Ohar Points 117
const myMap = new Map(
    Object
        .keys(myObj)
        .map(
            key => [key, myObj[key]]
        )
)

2 votes

Fusion des solutions de @Ohar et @TJCrowder : var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]])); .

1 votes

Merci, car j'avais aussi besoin de trier les clés des objets !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X