Jusqu'à présent, nous avons découvert les structures de données complexes suivantes :
Les objets sont utilisés pour stocker des collections à clés.
Les tableaux sont utilisés pour stocker des collections ordonnées.
Mais cela ne suffit pas pour la vraie vie. C'est pourquoi Map
et Set
existent également.
Map est une collection d'éléments de données à clé, tout comme un Object
. Mais la principale différence est que Map
autorise les clés de tout type.
Les méthodes et propriétés sont :
new Map()
– crée la carte.
map.set(key, value)
– stocke la valeur par la clé.
map.get(key)
– renvoie la valeur par la clé, undefined
si key
n'existe pas dans la carte.
map.has(key)
– renvoie true
si la key
existe, false
sinon.
map.delete(key)
– supprime l'élément (la paire clé/valeur) par la clé.
map.clear()
– supprime tout de la carte.
map.size
– renvoie le nombre d’éléments actuel.
Par exemple:
laissez map = new Map(); map.set('1', 'str1'); // une clé de chaîne map.set(1, 'num1'); // une touche numérique map.set(true, 'bool1'); // une clé booléenne // vous vous souvenez de l'objet normal ? cela convertirait les clés en chaîne // Map conserve le type, donc ces deux-là sont différents : alerte( map.get(1) ); // 'num1' alerte( map.get('1') ); // 'str1' alerte( map.size ); // 3
Comme nous pouvons le constater, contrairement aux objets, les clés ne sont pas converties en chaînes. Tout type de clé est possible.
map[key]
n'est pas la bonne façon d'utiliser une Map
Bien que map[key]
fonctionne également, par exemple, nous pouvons définir map[key] = 2
, cela traite map
comme un simple objet JavaScript, cela implique donc toutes les limitations correspondantes (uniquement les clés de chaîne/symbole, etc.).
Nous devrions donc utiliser les méthodes map
: set
, get
et ainsi de suite.
La carte peut également utiliser des objets comme clés.
Par exemple:
laissez john = { nom : "John" } ; // pour chaque utilisateur, stockons le nombre de visites laissez visitsCountMap = new Map(); // John est la clé de la carte visitesCountMap.set(john, 123); alert( visitsCountMap.get(john) ); // 123
L’utilisation d’objets comme clés est l’une des fonctionnalités Map
les plus remarquables et les plus importantes. La même chose ne compte pas pour Object
. La chaîne comme clé dans Object
est très bien, mais nous ne pouvons pas utiliser un autre Object
comme clé dans Object
.
Essayons :
laissez john = { nom : "John" } ; laissez ben = { nom : "Ben" } ; laissez visitsCountObj = {}; // essaie d'utiliser un objet visitesCountObj[ben] = 234 ; // essayez d'utiliser l'objet ben comme clé visitesCountObj[john] = 123 ; // essayez d'utiliser l'objet John comme clé, l'objet Ben sera remplacé // C'est ce qui a été écrit ! alert( visitsCountObj["[object Object]"] ); // 123
Comme visitsCountObj
est un objet, il convertit toutes les clés Object
, telles que john
et ben
ci-dessus, en la même chaîne "[object Object]"
. Certainement pas ce que nous voulons.
Comment Map
compare les clés
Pour tester l'équivalence des clés, Map
utilise l'algorithme SameValueZero. C'est à peu près la même chose que l'égalité stricte ===
, mais la différence est que NaN
est considéré comme égal à NaN
. NaN
peut donc également être utilisé comme clé.
Cet algorithme ne peut pas être modifié ou personnalisé.
Chaînage
Chaque appel map.set
renvoie la carte elle-même, nous pouvons donc « enchaîner » les appels :
map.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1');
Pour parcourir une map
, il existe 3 méthodes :
map.keys()
– renvoie un itérable pour les clés,
map.values()
– renvoie un itérable pour les valeurs,
map.entries()
– renvoie un itérable pour les entrées [key, value]
, il est utilisé par défaut dans for..of
.
Par exemple:
laissez recetteMap = new Map([ ['concombre', 500], ['tomates', 350], ['oignon', 50] ]); // itérer sur les clés (légumes) pour (laisser légume de recetteMap.keys()) { alerte (légume); // concombre, tomates, oignon } // itérer sur les valeurs (montants) pour (laisser la quantité de recetteMap.values()) { alerte(montant); // 500, 350, 50 } // itérer sur les entrées [clé, valeur] for (laisser l'entrée de RecipeMap) { // identique à RecipeMap.entries() alerte (entrée); // concombre, 500 (et ainsi de suite) }
L'ordre d'insertion est utilisé
L'itération se déroule dans le même ordre que celui dans lequel les valeurs ont été insérées. Map
préserve cet ordre, contrairement à un Object
normal.
En plus de cela, Map
a une méthode forEach
intégrée, similaire à Array
:
// exécute la fonction pour chaque paire (clé, valeur) recetteMap.forEach( (valeur, clé, carte) => { alert(`${key} : ${value}`); // concombre : 500 etc });
Lorsqu'une Map
est créée, nous pouvons transmettre un tableau (ou un autre itérable) avec des paires clé/valeur pour l'initialisation, comme ceci :
// tableau de paires [clé, valeur] laissez map = nouvelle carte ([ ['1', 'str1'], [1, 'num1'], [vrai, 'bool1'] ]); alerte( map.get('1') ); // chaîne1
Si nous avons un objet simple et que nous souhaitons créer une Map
à partir de celui-ci, nous pouvons alors utiliser la méthode intégrée Object.entries(obj) qui renvoie un tableau de paires clé/valeur pour un objet exactement dans ce format.
Nous pouvons donc créer une carte à partir d'un objet comme ceci :
soit obj = { nom : "Jean", âge : 30 ans } ; let map = new Map(Object.entries(obj)); alert( map.get('nom') ); // John
Ici, Object.entries
renvoie le tableau de paires clé/valeur : [ ["name","John"], ["age", 30] ]
. C'est ce dont Map
a besoin.
Nous venons de voir comment créer Map
à partir d'un objet simple avec Object.entries(obj)
.
Il existe une méthode Object.fromEntries
qui fait l'inverse : étant donné un tableau de paires [key, value]
, elle crée un objet à partir d'elles :
laissez les prix = Object.fromEntries([ ['banane', 1], ['orange', 2], ['viande', 4] ]); // maintenant prix = { banane : 1, orange : 2, viande : 4 } alerte (prix.orange); // 2
Nous pouvons utiliser Object.fromEntries
pour obtenir un objet simple à partir de Map
.
Par exemple, nous stockons les données dans un Map
, mais nous devons les transmettre à un code tiers qui attend un objet simple.
On y va:
laissez map = new Map(); map.set('banane', 1); map.set('orange', 2); map.set('viande', 4); let obj = Object.fromEntries(map.entries()); // crée un objet simple (*) // fait! // obj = { banane : 1, orange : 2, viande : 4 } alerte(obj.orange); // 2
Un appel à map.entries()
renvoie un itérable de paires clé/valeur, exactement au bon format pour Object.fromEntries
.
Nous pourrions également raccourcir la ligne (*)
:
let obj = Object.fromEntries(map); // omettre .entries()
C'est la même chose, car Object.fromEntries
attend un objet itérable comme argument. Pas nécessairement un tableau. Et l'itération standard pour map
renvoie les mêmes paires clé/valeur que map.entries()
. Nous obtenons donc un objet simple avec les mêmes clés/valeurs que le map
.
Un Set
est une collection de type spécial – « ensemble de valeurs » (sans clés), où chaque valeur ne peut apparaître qu'une seule fois.
Ses principales méthodes sont :
new Set([iterable])
– crée l’ensemble et si un objet iterable
est fourni (généralement un tableau), en copie les valeurs dans l’ensemble.
set.add(value)
– ajoute une valeur, renvoie l'ensemble lui-même.
set.delete(value)
– supprime la valeur, renvoie true
si value
existait au moment de l'appel, sinon false
.
set.has(value)
– renvoie true
si la valeur existe dans l'ensemble, sinon false
.
set.clear()
– supprime tout de l’ensemble.
set.size
– est le nombre d’éléments.
La principale caractéristique est que les appels répétés de set.add(value)
avec la même valeur ne font rien. C'est la raison pour laquelle chaque valeur n'apparaît dans un Set
qu'une seule fois.
Par exemple, nous recevons des visiteurs et nous aimerions nous souvenir de tout le monde. Mais les visites répétées ne doivent pas conduire à des doublons. Un visiteur ne doit être « compté » qu’une seule fois.
Set
est exactement ce qu'il faut pour cela :
laissez set = new Set(); laissez john = { nom : "John" } ; laissez pete = { nom : "Pete" } ; laissez mary = { nom : "Marie" } ; // visites, certains utilisateurs viennent plusieurs fois set.add(john); set.add(pete); set.add(marie); set.add(john); set.add(marie); // set ne conserve que les valeurs uniques alerte( set.size ); // 3 pour (laisser l'utilisateur de l'ensemble) { alert(utilisateur.nom); // John (puis Pete et Mary) }
L'alternative à Set
pourrait être un tableau d'utilisateurs et le code permettant de vérifier les doublons à chaque insertion à l'aide de arr.find. Mais les performances seraient bien pires, car cette méthode parcourt l’ensemble du tableau en vérifiant chaque élément. Set
est bien mieux optimisé en interne pour les contrôles d’unicité.
Nous pouvons parcourir un ensemble soit avec for..of
, soit en utilisant forEach
:
let set = new Set(["oranges", "pommes", "bananes"]); pour (laisser la valeur de l'ensemble) alert(value); // pareil avec forEach : set.forEach((valeur, valeurAgain, set) => { alerte (valeur); });
Notez la chose amusante. La fonction de rappel passée forEach
a 3 arguments : une value
, puis la même valeur valueAgain
, et enfin l'objet cible. En effet, la même valeur apparaît deux fois dans les arguments.
C'est pour des raisons de compatibilité avec Map
où le rappel passé forEach
a trois arguments. Cela a l’air un peu étrange, c’est sûr. Mais cela peut aider à remplacer facilement Map
par Set
dans certains cas, et vice versa.
Les mêmes méthodes que Map
pour les itérateurs sont également prises en charge :
set.keys()
– renvoie un objet itérable pour les valeurs,
set.values()
– identique à set.keys()
, pour la compatibilité avec Map
,
set.entries()
– renvoie un objet itérable pour les entrées [value, value]
, existe pour la compatibilité avec Map
.
Map
– est une collection de valeurs clés.
Méthodes et propriétés :
new Map([iterable])
– crée la carte, avec iterable
facultatif (par exemple un tableau) de paires [key,value]
pour l'initialisation.
map.set(key, value)
– stocke la valeur par la clé, renvoie la carte elle-même.
map.get(key)
– renvoie la valeur par la clé, undefined
si key
n'existe pas dans la carte.
map.has(key)
– renvoie true
si la key
existe, false
sinon.
map.delete(key)
– supprime l'élément par la clé, renvoie true
si key
existait au moment de l'appel, sinon false
.
map.clear()
– supprime tout de la carte.
map.size
– renvoie le nombre d’éléments actuel.
Les différences par rapport à un Object
classique :
Toutes les clés, tous les objets peuvent être des clés.
Méthodes pratiques supplémentaires, la propriété size
.
Set
– est une collection de valeurs uniques.
Méthodes et propriétés :
new Set([iterable])
– crée l'ensemble, avec iterable
facultatif (par exemple un tableau) de valeurs pour l'initialisation.
set.add(value)
– ajoute une valeur (ne fait rien si value
existe), renvoie l'ensemble lui-même.
set.delete(value)
– supprime la valeur, renvoie true
si value
existait au moment de l'appel, sinon false
.
set.has(value)
– renvoie true
si la valeur existe dans l'ensemble, sinon false
.
set.clear()
– supprime tout de l’ensemble.
set.size
– est le nombre d’éléments.
L'itération sur Map
et Set
est toujours dans l'ordre d'insertion, nous ne pouvons donc pas dire que ces collections ne sont pas ordonnées, mais nous ne pouvons pas réorganiser les éléments ou obtenir directement un élément par son numéro.
importance : 5
Soit arr
un tableau.
Créez une fonction unique(arr)
qui doit renvoyer un tableau avec des éléments uniques de arr
.
Par exemple:
fonction unique(arr) { /* votre code */ } let valeurs = ["Lièvre", "Krishna", "Lièvre", "Krishna", "Krishna", "Krishna", "Lièvre", "Lièvre", ":-O" ]; alert( unique(valeurs) ); // Lièvre, Krishna, :-O
PS Ici, les chaînes sont utilisées, mais peuvent être des valeurs de n'importe quel type.
PPS Utilisez Set
pour stocker des valeurs uniques.
Ouvrez un bac à sable avec des tests.
fonction unique(arr) { return Array.from(new Set(arr)); }
Ouvrez la solution avec des tests dans un bac à sable.
importance : 4
Les anagrammes sont des mots qui ont le même nombre de mêmes lettres, mais dans un ordre différent.
Par exemple:
sieste - poêle oreille - sont - époque tricheurs - hectares - professeurs
Écrivez une fonction aclean(arr)
qui renvoie un tableau nettoyé des anagrammes.
Par exemple:
let arr = ["nap", "profs", "tricheurs", "PAN", "ear", "era", "hectares"]; alert( aclean(arr) ); // "sieste,profs,oreille" ou "PAN,tricheurs,ère"
De chaque groupe d’anagrammes ne doit rester qu’un seul mot, quel que soit celui-ci.
Ouvrez un bac à sable avec des tests.
Pour trouver toutes les anagrammes, divisons chaque mot en lettres et trions-les. Une fois triés par lettres, toutes les anagrammes sont identiques.
Par exemple:
sieste, pan -> anp oreille, époque, sont -> aer tricheurs, hectares, professeurs -> aceehrst ...
Nous utiliserons les variantes triées par lettres comme clés de mappage pour stocker une seule valeur pour chaque clé :
fonction aclean(arr) { laissez map = new Map(); pour (que le mot d'arr) { // divise le mot par lettres, les trie et les rejoint let sorted = word.toLowerCase().split('').sort().join(''); // (*) map.set (trié, mot); } return Array.from(map.values()); } let arr = ["nap", "profs", "tricheurs", "PAN", "ear", "era", "hectares"]; alert( aclean(arr) );
Le tri des lettres se fait par la chaîne d'appels dans la ligne (*)
.
Pour plus de commodité, divisons-le en plusieurs lignes :
laisser trié = mot // PAN .toLowerCase() // panoramique .split('') // ['p','a','n'] .sort() // ['a','n','p'] .rejoindre(''); // anp
Deux mots différents 'PAN'
et 'nap'
reçoivent la même forme 'anp'
triée par lettres.
La ligne suivante met le mot sur la carte :
map.set (trié, mot);
Si jamais nous rencontrons à nouveau un mot sous la même forme triée par lettres, il écrasera la valeur précédente avec la même clé dans la carte. Nous aurons donc toujours au maximum un mot par forme de lettre.
À la fin, Array.from(map.values())
prend un itérable sur les valeurs de la carte (nous n'avons pas besoin de clés dans le résultat) et en renvoie un tableau.
Ici, nous pourrions également utiliser un objet simple au lieu du Map
, car les clés sont des chaînes.
Voici à quoi peut ressembler la solution :
fonction aclean(arr) { soit obj = {} ; pour (soit i = 0; i < arr.length; i++) { let sorted = arr[i].toLowerCase().split("").sort().join(""); obj[trié] = arr[i]; } return Object.values(obj); } let arr = ["nap", "profs", "tricheurs", "PAN", "ear", "era", "hectares"]; alert( aclean(arr) );
Ouvrez la solution avec des tests dans un bac à sable.
importance : 5
Nous aimerions obtenir un tableau de map.keys()
dans une variable, puis lui appliquer des méthodes spécifiques au tableau, par exemple .push
.
Mais ça ne marche pas :
laissez map = new Map(); map.set("nom", "Jean"); laissez clés = map.keys(); // Erreur : keys.push n'est pas une fonction touches.push("plus");
Pourquoi? Comment pouvons-nous corriger le code pour que keys.push
fonctionne ?
C'est parce que map.keys()
renvoie un itérable, mais pas un tableau.
Nous pouvons le convertir en tableau en utilisant Array.from
:
laissez map = new Map(); map.set("nom", "Jean"); let clés = Array.from(map.keys()); touches.push("plus"); alerte (clés); // nom, plus