Javascript • Système de types • Collections
Introduction
Section intitulée « Introduction »Dans cette série d’articles, nous faisons un focus sur les fonctionnalités de base de Javascript.
Cet article concerne le système de types proposé par Javascript. Nous allons détailler maintenant les types de collection.
Système de types en Javascript
Section intitulée « Système de types en Javascript »Typage dynamique
Section intitulée « Typage dynamique »Javascript possède un typage dynamique. Qu’est-ce-que cela signifie exactement ?
🔑 Nous ne déclarons pas le type d’une variable avant de l’utiliser.
🔑 Le type d’une variable est déterminé à l’exécution (et pas à la compilation).
🔑 Le type d’une variable peut changer pendant sa durée de vie.
// toto est une chaine de caractères (string)let toto = "text";
// toto est maintenant un nombre (number)toto = 69;
// toto est maintenant un booléen (boolean)toto = true;Typage faible
Section intitulée « Typage faible »Javascript est également faiblement typé. Il permet ainsi des conversions implicites de type.
const oneTwoThree = 123; // numberconst fourFive = "45"; // stringconst result = oneTwoThree + fourFive; // stringconsole.log(result); // ← "12345"Les types Objet
Section intitulée « Les types Objet »Le typage Javascript est divisé en deux mondes : les types de valeurs primitives (ou types primitifs) et les types objet. Les types Objet regroupent :
- le type objet (Object) ;
- le type tableau (Array) ;
- le type fonction (Function) ;
- le type class (Class).
Les types objet sont des types référence (reference type) : une variable d’un type object contient la référence à la valeur. Nous pouvons aussi dire qu’elle pointe vers cette valeur.
Les variables d’un type objet sont muables (mutable ) : nous pouvons changer la valeur d’un objet après sa création, contrairement aux valeurs primitives.
Nous allons maintenant nous concentrer dans cet article sur les collections
Le type array est un type d’objet qui permet de stocker une collection indexée.
Les éléments de cette collection peuvent être de n’importe quel type.
La collection n’est pas forcément homogène : tous les éléments ne sont pas forcément du même type.
Chaque élément est associé à un index.
L’index est un nombre entier positif.
Le premier index vaut 0 (et pas 1).
const mixedArray = [ "ABC", // type = string, index = 0 (x, y) => x + y, // type = function, index = 1 null, // type = null, index = 2 -123, // type = number, index = 3 undefined, // type = undefined, index = 4 { name: "Bob" }, // type = object, index = 5 [ 7, "X" ], // type = array, index = 6 { height: 16, width: 32 } // type = object, index = 7];L’object wrapper associé à array est :
Array.
Il propose de très nombreuses méthodes dont certaines sont présentées dans cet article.
Initialisation
Section intitulée « Initialisation »Comme nous venons de le voir dans les deux exemples précédents,
nous pouvons créer une variable contenant un tableau en utilisant la syntaxe [].
Le tableau sera créé et rempli avec les valeurs entre [ et ].
const emptyArray = [];const fibonacciSequence = [ 0, 1, 2, 3, 5, 8, 13, 21 ];const primaryColors = [ "blue", "green", "red" ];Nous pouvons également utiliser le constructeur de tableau new Array().
const emptyArray = new Array();const fibonacciSequence = new Array(0, 1, 2, 3, 5, 8, 13, 21);const primaryColors = new Array("blue", "green", "red");Propriété length
Section intitulée « Propriété length »Une variable de type array possède la propriété length.
La valeur de length est toujours égale à la valeur de l’index le plus élevé + 1.
length ne représente donc pas forcément le nombre d’éléments du tableau.
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
console.log(mixedArray.length); // ← 8Valeur d’un élément
Section intitulée « Valeur d’un élément »Nous pouvons accéder à un élément d’un tableau via l’indexeur [].
La valeur entre [ et ] correspond à l’index de l’élément que nous souhaitons récupérer.
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
console.log(mixedArray[0]); // ← "ABC"console.log(mixedArray[1]); // ← function 1(x, y)console.log(mixedArray[2]); // ← nullconsole.log(mixedArray[3]); // ← -123console.log(mixedArray[4]); // ← undefinedconsole.log(mixedArray[5]); // ← Object { name: "Bob" }console.log(mixedArray[6]); // ← Array [ 7, "X" ]console.log(mixedArray[7]); // ← Object { height: 16, width: 32 }console.log(mixedArray[8]); // ← undefinedconsole.log(mixedArray[9]); // ← undefinedconsole.log(mixedArray[10]); // ← undefinedconsole.log(mixedArray.length); // ← 8Si l’index n’existe pas alors undefined est retourné.
Écriture d’un élément
Section intitulée « Écriture d’un élément »Nous pouvons créer ou modifier un élement en utilisant l’indexeur [].
La valeur entre [ et ] correspond à l’index de l’élément que nous souhaitons créer ou modifier.
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
mixedArray[0] = (a, b) => a - b;mixedArray[1] = "DEF";mixedArray[2] = 3.1415;mixedArray[10] = [ 10, 9, 8 ];mixedArray["prop"] = "val";
console.log(mixedArray[0]); // ← function 0(a, b)console.log(mixedArray[1]); // ← "DEF"console.log(mixedArray[2]); // ← 3.1415console.log(mixedArray[3]); // ← -123console.log(mixedArray[4]); // ← undefinedconsole.log(mixedArray[5]); // ← Object { name: "Bob" }console.log(mixedArray[6]); // ← Array [ 7, "X" ]console.log(mixedArray[7]); // ← Object { height: 16, width: 32 }console.log(mixedArray[8]); // ← undefinedconsole.log(mixedArray[9]); // ← undefinedconsole.log(mixedArray[10]); // ← Array(3) [ 10, 9, 8 ]console.log(mixedArray.length); // ← 11console.log(mixedArray.prop); // ← "val"Itération
Section intitulée « Itération »Nous pouvons utiliser l’instruction for…of pour obtenir toutes les valeurs d’un tableau.
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
// ← "ABC"// ← function mixedArray(x, y)// ← null// ← -123// ← undefined// ← Object { name: "Bob" }// ← Array [ 7, "X" ]// ← Object { height: 16, width: 32 }for (const element of mixedArray) { console.log(element);}Nous pouvons également utiliser la méthode d’instance Array.prototype.forEach().
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
// ← [0] : "ABC"// ← [1] : function mixedArray(x, y)// ← [2] : null// ← [3] : -123// ← [4] : undefined// ← [5] : Object { name: "Bob" }// ← [6] : Array [ 7, "X" ]// ← [7] : Object { height: 16, width: 32 }mixedArray.forEach((element, index) => console.log(`[${index}] :`, element));Finalement, nous pouvons utiliser l’instruction for.
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
// ← [0] : "ABC"// ← [1] : function mixedArray(x, y)// ← [2] : null// ← [3] : -123// ← [4] : undefined// ← [5] : Object { name: "Bob" }// ← [6] : Array [ 7, "X" ]// ← [7] : Object { height: 16, width: 32 }for (let index = 0; index < mixedArray.length; index++) { console.log(`[${index}] :`, mixedArray[index])}Comme pour le type objet, nous pouvons effectuer une copie superficielle grace au spread operator (…).
const mixedArray = [ "ABC", (x, y) => x + y, null, -123, undefined, { name: "Bob" }, [ 7, "X" ], { height: 16, width: 32 }];
const copyOfMixedArray = [ "before", ...mixedArray, "after" ];
// ← [0] : "before"// ← [1] : "ABC"// ← [2] : function mixedArray(x, y)// ← [3] : null// ← [4] : -123// ← [5] : undefined// ← [6] : Object { name: "Bob" }// ← [7] : Array [ 7, "X" ]// ← [8] : Object { height: 16, width: 32 }// ← [9] : "after"copyOfMixedArray.forEach((element, index) => console.log(`[${index}] :`, element));
console.log(copyOfMixedArray.length); // ← 10Le tableau copyOfMixedArray contient :
- l’élément “before” (index 0)
- la liste des éléments du tableau
mixedArrayvia...mixedArray(index 1 à 8) ; - l’élément “after” (index 9)
Tableau multi-dimensionnel
Section intitulée « Tableau multi-dimensionnel »Les tableaux peuvent être imbriqués : chaque élément d’un tableau peut lui-même être un autre tableau. Nous pouvons ainsi créer un tableau multi-dimensionnel.
const multidimensionalArray = new Array(3); // Nouveau tableau de 3 éléments
for (let i = 0; i < 3; i++) { multidimensionalArray[i] = new Array(3); for (let j = 0; j < 3; j++) { multidimensionalArray[i][j] = `[${i} → ${j}]`; }}
// ← Array(3) [ (3) […], (3) […], (3) […] ]// 0: Array(3) [ "[0 → 0]", "[0 → 1]", "[0 → 2]" ]// 1: Array(3) [ "[1 → 0]", "[1 → 1]", "[1 → 2]" ]// 2: Array(3) [ "[2 → 0]", "[2 → 1]", "[2 → 2]" ]// length: 3console.log(multidimensionalArray);Le type Map permet de stocker une collection de paires de clef-valeur (key-value pairs). Il fait partie des collections avec clef.
Le type object permet lui aussi de stocker une collection de clef-valeur.
Il y a cependant des différences.
| Caractéristique | Map | Object |
|---|---|---|
| Clefs accidentelles | Map ne contient aucune clé par défaut. Il ne contient que les éléments que nous avons explicitement ajoutés. | Object possède un prototype et dispose donc de certaines clefs par défaut, ce qui peut être source de collision avec nos propres clefs si nous ne sommes pas vigilants. |
| Types de clef | Map accepte n’importe quel type de valeur (primitive ou objet) comme clef. | Object accepte uniquement le type string ou symbol comme clef. |
| Ordre des éléments | Map respecte l’ordre d’insertion des éléments. | Object ne garantie pas l’ordre des éléments. Cet ordre dépends également de l’itération utilisée. |
| Taille | Le nombre d’éléments est accessible avec la propriété size. | Le nombre d’éléments d’un Object doit être déterminé manuellement. |
| Itération | Map est un itérable et peut-être itéré via for…of. | Object n’est pas directement itérable. Nous pouvons néanmoins utiliser for…in. |
| Performances | Map propose de meilleures performances en cas de nombreuses ajouts/modifications/suppressions d’éléments. | Object ne propose pas d’optimisation particulière. |
| Sérialisation et désérialisation | Map ne propose pas de prise en charge native de la sérialisation/désérialisation. Il est néanmoins possible d’y arriver en fournissant une fonction de conversion à JSON.stringify() et JSON.parse(). | Object est nativement sérialisable. |
Le type Map est équivalent au type .NET
Dictionary<TKey,TValue>.
Initialisation
Section intitulée « Initialisation »Nous pouvons créer une variable de type Map en utilisant le constructeur
new Map().
const emptyMap = new Map();console.log(emptyMap); // ← Map(0)Le constructeur accepte comme paramètre un itérable dont les éléments sont des clefs-valeurs.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [5, "vendredi"], [6, "samedi"], [7, "dimanche"]]);
// ← Map(7) {// 1 → "lundi",// 2 → "mardi",// 3 → "mercredi",// 4 → "jeudi",// 5 → "vendredi",// 6 → "samedi",// 7 → "dimanche"// }console.log(weekDays);Propriété size
Section intitulée « Propriété size »La propriété d’instance
Map.prototype.size
retourne le nombre d’éléments courant d’une variable de type Map.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [5, "vendredi"], [6, "samedi"], [7, "dimanche"]]);
console.log(weekDays.size); // ← 7Lecture d’un élément
Section intitulée « Lecture d’un élément »La méthode d’instance Map.prototype.get(key) retourne la valeur associée à la clef passée en paramètre de la fonction.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [5, "vendredi"], [6, "samedi"], [7, "dimanche"]]);
console.log(weekDays.get(0)); // ← undefinedconsole.log(weekDays.get(1)); // ← "lundi"console.log(weekDays.get(2)); // ← "mardi"console.log(weekDays.get("3")); // ← undefinedSi aucun élément ne correspond à la clef spécifiée alors undefined est retourné.
Écriture d’un élément
Section intitulée « Écriture d’un élément »La méthode d’instance Map.prototype.set(key, value) permet de créer ou modifier la valeur associée à la clef.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [6, "samedi"], [7, "dimanche"]]);
weekDays.set(5, "vendredi");weekDays.set(7, "Dimanche");
// ← Map(7) {// 1 → "lundi",// 2 → "mardi",// 3 → "mercredi",// 4 → "jeudi",// 6 → "samedi",// 7 → "Dimanche"// 5 → "vendredi",// }console.log(weekDays);Suppression d’un élément
Section intitulée « Suppression d’un élément »La méthode d’instance Map.prototype.delete(key) permet de supprimer l’élément associé à la clef.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [6, "samedi"], [7, "dimanche"]]);
weekDays.delete(1); // ← trueweekDays.delete("1"); // ← false
// ← Map(6) {// 2 → "mardi",// 3 → "mercredi",// 4 → "jeudi",// 6 → "samedi",// 7 → "Dimanche"// 5 → "vendredi",// }console.log(weekDays);La méthode delete() retourne true si l’élément a bien été supprimé, sinon elle retourne false.
Suppression de tous les éléments
Section intitulée « Suppression de tous les éléments »La méthode d’instance Map.prototype.clear(key) permet de supprimer tous les éléments.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [6, "samedi"], [7, "dimanche"]]);
weekDays.clear();
console.log(weekDays); // ← Map(0)Existence d’un élément
Section intitulée « Existence d’un élément »La méthode d’instance
Map.prototype.has(key)
retourne true si un élément avec la clef spécifiée est présent dans la variable de type Map.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [5, "vendredi"], [6, "samedi"], [7, "dimanche"]]);
console.log(weekDays.has(0)); // ← falseconsole.log(weekDays.has(1)); // ← trueconsole.log(weekDays.has(2)); // ← trueconsole.log(weekDays.has("3")); // ← falseItération
Section intitulée « Itération »Nous pouvons utiliser l’instruction
for…of
pour obtenir tous les éléments d’une variable de type Map.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [5, "vendredi"], [6, "samedi"], [7, "dimanche"]]);
// ← Array [ 1, "lundi" ]// ← Array [ 2, "mardi" ]// ← Array [ 3, "mercredi" ]// ← Array [ 4, "jeudi" ]// ← Array [ 5, "vendredi" ]// ← Array [ 6, "samedi" ]// ← Array [ 7, "dimanche" ]for (const day of weekDays) { console.log(day);}La méthode d’instance Map.prototype.forEach(callbackFn) permet également de parcourir tous les éléments.
const weekDays = new Map([ [1, "lundi"], [2, "mardi"], [3, "mercredi"], [4, "jeudi"], [5, "vendredi"], [6, "samedi"], [7, "dimanche"]]);
// ← 1 → "lundi"// ← 2 → "mardi"// ← 3 → "mercredi"// ← 4 → "jeudi"// ← 5 → "vendredi"// ← 6 → "samedi"// ← 7 → "dimanche"weekDays.forEach((value, key) => { console.log(`${key} → ${value}`);});Le type Set permet de stocker une collection de valeurs uniques :chaque valeur ne peut apparaitre qu’une seule fois.
Une variable de type Set conserve l’ordre d’insertion.
Afin de faciliter la compréhension, nous pouvons considérer qu’une variable de type Set
est l’équivalent d’un variable de type Map avec clef = valeur.
Contrairement à une variable de type array, une variable de type Set n’est pas directement sérialisable.
Nous pouvons facilement contourner cette limitation en utilisant la méthode d’instance
Set.prototype.entries()
qui retourne tous les éléments sous forme de tableau.
Initialisation
Section intitulée « Initialisation »Nous pouvons créer une variable de type Map en utilisant le constructeur
new Set().
const emptySet = new Set();console.log(emptySet); // ← Set(0)Le constructeur accepte comme paramètre un itérable.
const primaryColors = new Set(["red", "green", "blue"]);
console.log(primaryColors); // ← Set(3) [ "red", "green", "blue" ]Propriété size
Section intitulée « Propriété size »La propriété d’instance
Set.prototype.size
retourne le nombre d’éléments courant d’une variable de type Set.
const primaryColors = new Set(["red", "green", "blue"]);
console.log(primaryColors.size); // ← 3Ajout d’un élément
Section intitulée « Ajout d’un élément »La méthode d’instance Set.prototype.add(element) permet d’ajouter un nouvel élément.
const primaryColors = new Set(["red"]);
primaryColors.add("green");primaryColors.add("blue").add("red");
console.log(primaryColors); // ← Set(3) [ "red", "green", "blue" ]La méthode add() retourne l’instance du Set afin de pouvoir chainer les appels de méthode.
Si un élément existe déjà alors la méthode add() n’a aucun effet.
Suppression d’un élément
Section intitulée « Suppression d’un élément »La méthode d’instance Set.prototype.delete(element) permet de supprimer l’élément.
const primaryColors = new Set(["red", "green", "blue", "black"]);
primaryColors.delete("black"); // ← trueprimaryColors.delete("white"); // ← false
console.log(primaryColors); // ← Set(3) [ "red", "green", "blue" ]La méthode delete() retourne true si l’élément a bien été supprimé, sinon elle retourne false.
Suppression de tous les éléments
Section intitulée « Suppression de tous les éléments »La méthode d’instance Set.prototype.clear() permet de supprimer tous les éléments.
const primaryColors = new Set(["red", "green", "blue"]);
primaryColors.clear();
console.log(primaryColors); // ← Set(0)Existence d’un élément
Section intitulée « Existence d’un élément »La méthode d’instance
Set.prototype.has(element)
retourne true si l’élément est présent dans la variable de type Set.
const primaryColors = new Set(["red", "green", "blue"]);
primaryColors.has("red"); // ← trueprimaryColors.has("Red"); // ← falseprimaryColors.has("green"); // ← trueItération
Section intitulée « Itération »Nous pouvons utiliser l’instruction
for…of
pour obtenir tous les éléments d’une variable de type Set.
const primaryColors = new Set(["red", "green", "blue"]);
// ← "red"// ← "green"// ← "blue"for (const color of primaryColors) { console.log(color);}La méthode d’instance Set.prototype.forEach(callbackFn) permet également de parcourir tous les éléments.
const primaryColors = new Set(["red", "green", "blue"]);
// ← "red"// ← "green"// ← "blue"primaryColors.forEach(color => { console.log(color);});Conclusion
Section intitulée « Conclusion »Nous avons vu les principaux types de collection.
Le type array est le type de collection le plus ancien proposé par Javascript.
Il dispose de méthodes d’instance puissantes pour effectuer de nombreuses manipulations.
Certaines de ces méthodes sont présentées dams cet article.
Les types Map et Set sont plus récents.
Map nous permet de créer un dictionnaire. Dans certains cas, il peut avantageusement remplacer un object qui remplissait historiquement cette fonction.
Set nous permet de créer une collection sans doublon. Cela peut nous être très utile dans certaines situations.
Dans l’article suivant, nous allons détailler le type function proposé par Javascript.