Les deux structures de données les plus utilisées en JavaScript sont Object
et Array
.
Les objets nous permettent de créer une entité unique qui stocke les éléments de données par clé.
Les tableaux nous permettent de rassembler des éléments de données dans une liste ordonnée.
Cependant, lorsque nous les transmettons à une fonction, nous n’en aurons peut-être pas besoin en totalité. La fonction peut nécessiter uniquement certains éléments ou propriétés.
L'affectation de déstructuration est une syntaxe spéciale qui nous permet de « décompresser » des tableaux ou des objets en un tas de variables, car c'est parfois plus pratique.
La déstructuration fonctionne également bien avec des fonctions complexes comportant de nombreux paramètres, valeurs par défaut, etc. Bientôt, nous verrons cela.
Voici un exemple de la façon dont un tableau est déstructuré en variables :
// nous avons un tableau avec un nom et un prénom let arr = ["John", "Smith"] // mission de déstructuration // définit firstName = arr[0] // et nom = arr[1] let [prénom, nom] = arr; alerte(prénom); // John alerte(nom); // Forgeron
Nous pouvons désormais travailler avec des variables au lieu des membres d'un tableau.
Cela a fière allure lorsqu'il est combiné avec des méthodes split
ou d'autres méthodes de retour de tableau :
let [prénom, nom] = "John Smith".split(' '); alerte(prénom); // John alerte(nom); // Forgeron
Comme vous pouvez le constater, la syntaxe est simple. Il y a cependant plusieurs détails particuliers. Voyons plus d'exemples pour mieux le comprendre.
« Déstructurant » ne veut pas dire « destructeur ».
C'est ce qu'on appelle « affectation déstructurante », car elle « déstructure » en copiant des éléments dans des variables. Toutefois, le tableau lui-même n’est pas modifié.
C'est juste une façon plus courte d'écrire :
// let [prénom, nom] = arr; laissez firstName = arr[0]; soit nom de famille = arr[1];
Ignorer les éléments en utilisant des virgules
Les éléments indésirables du tableau peuvent également être supprimés via une virgule supplémentaire :
// le deuxième élément n'est pas nécessaire let [firstName, , title] = ["Jules", "César", "Consul", "de la République romaine"] ; alerte( titre ); // Consul
Dans le code ci-dessus, le deuxième élément du tableau est ignoré, le troisième est affecté à title
et le reste des éléments du tableau est également ignoré (car il n'y a pas de variables pour eux).
Fonctionne avec n'importe quel itérable sur le côté droit
…En fait, nous pouvons l’utiliser avec n’importe quel itérable, pas seulement avec des tableaux :
soit [a, b, c] = "abc" ; // ["a", "b", "c"] let [un, deux, trois] = new Set([1, 2, 3]);
Cela fonctionne, car en interne, une mission de déstructuration fonctionne en itérant sur la bonne valeur. C'est une sorte de sucre de syntaxe pour appeler for..of
sur la valeur à droite de =
et attribuer les valeurs.
Attribuer à n'importe quoi sur le côté gauche
Nous pouvons utiliser n’importe quel « assignable » sur le côté gauche.
Par exemple, une propriété d'objet :
laissez l'utilisateur = {} ; [user.name, user.surname] = "John Smith".split(' '); alert(utilisateur.nom); // John alert(utilisateur.nom de famille); // Forgeron
Boucler avec .entries()
Dans le chapitre précédent, nous avons vu la méthode Object.entries(obj).
Nous pouvons l'utiliser avec la déstructuration pour parcourir les clés et valeurs d'un objet :
laissez l'utilisateur = { nom : "Jean", âge : 30 ans } ; // boucle sur les clés et valeurs for (let [clé, valeur] de Object.entries(user)) { alerte(`${clé}:${valeur}`); // nom :John, puis âge :30 }
Le code similaire pour une Map
est plus simple, car il est itérable :
laissez l'utilisateur = new Map(); user.set("nom", "Jean"); user.set("âge", "30"); // La carte itère sous forme de paires [clé, valeur], très pratique pour la déstructuration pour (laissez [clé, valeur] de l'utilisateur) { alerte(`${clé}:${valeur}`); // nom :John, puis âge :30 }
Astuce pour échanger des variables
Il existe une astuce bien connue pour échanger les valeurs de deux variables à l'aide d'une affectation de déstructuration :
laissez invité = "Jane" ; laissez admin = "Pete" ; // Échangeons les valeurs : make guest=Pete, admin=Jane [invité, administrateur] = [administrateur, invité] ; alerte(`${invité} ${admin}`); // Pete Jane (échange réussi !)
Ici, nous créons un tableau temporaire de deux variables et le déstructurons immédiatement dans un ordre permuté.
Nous pouvons échanger plus de deux variables de cette façon.
Habituellement, si le tableau est plus long que la liste de gauche, les éléments « supplémentaires » sont omis.
Par exemple, ici, seuls deux éléments sont pris en compte et le reste est simplement ignoré :
soit [nom1, nom2] = ["Jules", "César", "Consul", "de la République romaine"] ; alerte(nom1); // Jules alerte(nom2); // César // Les autres éléments ne sont attribués nulle part
Si nous souhaitons également rassembler tout ce qui suit – nous pouvons ajouter un paramètre supplémentaire qui obtient « le reste » en utilisant trois points "..."
:
let [name1, name2, ...rest] = ["Jules", "César", "Consul", "de la République romaine"] ; // rest est un tableau d'éléments, à partir du 3ème alerte(reste[0]); // Consul alerte(reste[1]); // de la République romaine alert(rest.length); // 2
La valeur de rest
est le tableau des éléments restants du tableau.
Nous pouvons utiliser n'importe quel autre nom de variable à la place de rest
, assurez-vous simplement qu'il est précédé de trois points et qu'il passe en dernier dans l'affectation de déstructuration.
let [name1, name2, ...titles] = ["Jules", "César", "Consul", "de la République romaine"] ; // maintenant titres = ["Consul", "de la République romaine"]
Si le tableau est plus court que la liste de variables à gauche, il n'y aura pas d'erreur. Les valeurs absentes sont considérées comme indéfinies :
laissez [prénom, nom] = []; alerte(prénom); // non défini alerte(nom); // non défini
Si nous voulons qu'une valeur « par défaut » remplace celle manquante, nous pouvons la fournir en utilisant =
:
// valeurs par défaut laissez [nom = "Invité", nom = "Anonyme"] = ["Julius"]; alerte(nom); // Julius (du tableau) alerte(nom); // Anonyme (utilisé par défaut)
Les valeurs par défaut peuvent être des expressions plus complexes ou même des appels de fonction. Ils sont évalués uniquement si la valeur n'est pas fournie.
Par exemple, nous utilisons ici la fonction prompt
pour deux valeurs par défaut :
// exécute uniquement une invite pour le nom de famille let [nom = prompt('nom?'), nom = prompt('nom?')] = ["Julius"]; alerte(nom); // Julius (du tableau) alerte(nom); // quelle que soit l'invite obtenue
Veuillez noter : l' prompt
s'exécutera uniquement pour la valeur manquante ( surname
).
La mission de déstructuration fonctionne également avec des objets.
La syntaxe de base est la suivante :
soit {var1, var2} = {var1 :…, var2 :…}
Nous devrions avoir un objet existant sur le côté droit, que nous souhaitons diviser en variables. Le côté gauche contient un « modèle » semblable à un objet pour les propriétés correspondantes. Dans le cas le plus simple, il s'agit d'une liste de noms de variables dans {...}
.
Par exemple:
laissez les options = { titre : "Menu", largeur : 100, hauteur : 200 } ; laissez {titre, largeur, hauteur} = options ; alerte(titre); // Menu alerte (largeur); // 100 alerte (hauteur); // 200
Les propriétés options.title
, options.width
et options.height
sont affectées aux variables correspondantes.
L'ordre n'a pas d'importance. Cela fonctionne aussi :
// a modifié l'ordre dans let {...} let {hauteur, largeur, titre} = { titre : "Menu", hauteur : 200, largeur : 100 }
Le modèle sur le côté gauche peut être plus complexe et spécifier le mappage entre les propriétés et les variables.
Si nous voulons attribuer une propriété à une variable avec un autre nom, par exemple, faites en sorte que options.width
aille dans la variable nommée w
, alors nous pouvons définir le nom de la variable en utilisant deux points :
laissez les options = { titre : "Menu", largeur : 100, hauteur : 200 } ; // { propriété source : variable cible } let {largeur : w, hauteur : h, titre} = options ; // largeur -> w // hauteur -> h // titre -> titre alerte(titre); // Menu alerte(w); // 100 alerte(h); // 200
Les deux points indiquent « quoi : va où ». Dans l'exemple ci-dessus, la width
de la propriété va à w
, height
de la propriété va à h
et title
est attribué au même nom.
Pour les propriétés potentiellement manquantes, nous pouvons définir des valeurs par défaut en utilisant "="
, comme ceci :
laissez les options = { titre : "Menu" } ; soit {largeur = 100, hauteur = 200, titre} = options ; alerte(titre); // Menu alerte (largeur); // 100 alerte (hauteur); // 200
Tout comme pour les tableaux ou les paramètres de fonction, les valeurs par défaut peuvent être n'importe quelle expression ou même des appels de fonction. Ils seront évalués si la valeur n'est pas fournie.
Dans le code ci-dessous, prompt
demande width
, mais pas title
:
laissez les options = { titre : "Menu" } ; let {width = prompt("width?"), title = prompt("title?")} = options; alerte(titre); // Menu alerte (largeur); // (quel que soit le résultat de l'invite)
Nous pouvons également combiner à la fois les deux points et l’égalité :
laissez les options = { titre : "Menu" } ; soit {largeur : w = 100, hauteur : h = 200, titre} = options ; alerte(titre); // Menu alerte(w); // 100 alerte(h); // 200
Si nous avons un objet complexe avec de nombreuses propriétés, nous pouvons extraire uniquement ce dont nous avons besoin :
laissez les options = { titre : "Menu", largeur : 100, hauteur : 200 } ; // extrait uniquement le titre en tant que variable laissez { titre } = options ; alerte(titre); // Menu
Que se passe-t-il si l’objet a plus de propriétés que nous n’avons de variables ? Pouvons-nous en prendre une partie et ensuite assigner le « reste » quelque part ?
Nous pouvons utiliser le modèle rest, tout comme nous l'avons fait avec les tableaux. Il n'est pas pris en charge par certains navigateurs plus anciens (IE, utilisez Babel pour le remplir), mais fonctionne dans les navigateurs modernes.
Cela ressemble à ceci :
laissez les options = { titre : "Menu", hauteur : 200, largeur : 100 } ; // titre = propriété nommée titre // rest = objet avec le reste des propriétés laissez {titre, ...reste} = options ; // maintenant title="Menu", rest={hauteur : 200, largeur : 100} alert(rest.hauteur); // 200 alert(rest.width); // 100
Je t'ai eu s'il n'y a pas de let
Dans les exemples ci-dessus, les variables ont été déclarées directement dans l'affectation : let {…} = {…}
. Bien sûr, nous pourrions également utiliser des variables existantes, sans let
. Mais il y a un piège.
Cela ne fonctionnera pas :
laissez le titre, la largeur, la hauteur ; // erreur dans cette ligne {titre, largeur, hauteur} = {titre : "Menu", largeur : 200, hauteur : 100} ;
Le problème est que JavaScript traite {...}
dans le flux de code principal (pas dans une autre expression) comme un bloc de code. De tels blocs de code peuvent être utilisés pour regrouper des instructions, comme ceci :
{ // un bloc de code let message = "Bonjour" ; //... alerte(message); }
Donc ici, JavaScript suppose que nous avons un bloc de code, c'est pourquoi il y a une erreur. Nous voulons plutôt une déstructuration.
Pour montrer à JavaScript qu'il ne s'agit pas d'un bloc de code, nous pouvons mettre l'expression entre parenthèses (...)
:
laissez le titre, la largeur, la hauteur ; // ok maintenant ({titre, largeur, hauteur} = {titre : "Menu", largeur : 200, hauteur : 100}) ; alerte( titre ); // Menu
Si un objet ou un tableau contient d'autres objets et tableaux imbriqués, nous pouvons utiliser des modèles de gauche plus complexes pour extraire des parties plus profondes.
Dans le code ci-dessous, options
ont un autre objet dans la propriété size
et un tableau dans la propriété items
. Le modèle sur le côté gauche de l'affectation a la même structure pour en extraire des valeurs :
laissez les options = { taille: { largeur : 100, hauteur : 200 }, éléments : ["Gâteau", "Donut"], supplémentaire : vrai } ; // affectation de déstructuration divisée en plusieurs lignes pour plus de clarté laisser { taille : { // mettre la taille ici largeur, hauteur }, items : [item1, item2], // attribuer des éléments ici title = "Menu" // non présent dans l'objet (la valeur par défaut est utilisée) } = options ; alerte(titre); // Menu alerte (largeur); // 100 alerte (hauteur); // 200 alerte (élément1); // Gâteau alerte (élément2); // Donut
Toutes les propriétés de l'objet options
, sauf extra
qui est absent dans la partie gauche, sont affectées aux variables correspondantes :
Enfin, nous avons width
, height
, item1
, item2
et title
à partir de la valeur par défaut.
Notez qu'il n'y a pas de variables pour size
et items
, car nous prenons plutôt leur contenu.
Il arrive parfois qu'une fonction comporte de nombreux paramètres, dont la plupart sont facultatifs. Cela est particulièrement vrai pour les interfaces utilisateur. Imaginez une fonction qui crée un menu. Il peut avoir une largeur, une hauteur, un titre, une liste d'éléments, etc.
Voici une mauvaise façon d'écrire une telle fonction :
function showMenu(titre = "Sans titre", largeur = 200, hauteur = 100, éléments = []) { //... }
Dans la vraie vie, le problème est de savoir comment mémoriser l’ordre des arguments. Habituellement, les IDE essaient de nous aider, surtout si le code est bien documenté, mais quand même… Un autre problème est de savoir comment appeler une fonction lorsque la plupart des paramètres sont ok par défaut.
Comme ça?
// non défini où les valeurs par défaut conviennent showMenu("Mon Menu", non défini, non défini, ["Article1", "Article2"])
C'est moche. Et devient illisible lorsque l’on traite plus de paramètres.
La déstructuration vient à la rescousse !
On peut passer des paramètres en tant qu'objet, et la fonction les déstructure immédiatement en variables :
// on passe l'objet à la fonction laissez les options = { titre : "Mon menu", éléments : ["Article1", "Article2"] } ; // ...et il l'étend immédiatement aux variables function showMenu({titre = "Sans titre", largeur = 200, hauteur = 100, éléments = []}) { // titre, éléments – extraits des options, // largeur, hauteur – valeurs par défaut utilisées alert( `${titre} ${width} ${hauteur}` ); // Mon Menu 200 100 alert( éléments ); // Article1, Article2 } showMenu(options);
Nous pouvons également utiliser une déstructuration plus complexe avec des objets imbriqués et des mappages deux-points :
laissez les options = { titre : "Mon menu", éléments : ["Article1", "Article2"] } ; fonction showMenu({ titre = "Sans titre", largeur : w = 100, // la largeur va à w hauteur : h = 200, // la hauteur va à h items : [item1, item2] // le premier élément des items va à item1, le deuxième à item2 }) { alerte( `${titre} ${w} ${h}` ); // Mon Menu 100 200 alerte( élément1 ); // Article1 alerte( élément2 ); // Article2 } showMenu(options);
La syntaxe complète est la même que pour une mission de déstructuration :
fonction({ incomingProperty : varName = valeur par défaut ... })
Ensuite, pour un objet de paramètres, il y aura une variable varName
pour la propriété incomingProperty
, avec defaultValue
par défaut.
Veuillez noter qu'une telle déstructuration suppose que showMenu()
ait un argument. Si nous voulons toutes les valeurs par défaut, alors nous devons spécifier un objet vide :
showMenu({}); // ok, toutes les valeurs sont par défaut showMenu(); // cela donnerait une erreur
Nous pouvons résoudre ce problème en faisant de {}
la valeur par défaut pour l'ensemble de l'objet des paramètres :
function showMenu({ titre = "Menu", largeur = 100, hauteur = 200 } = {}) { alert( `${titre} ${width} ${hauteur}` ); } showMenu(); // Menu 100 200
Dans le code ci-dessus, l'ensemble de l'objet arguments est {}
par défaut, il y a donc toujours quelque chose à déstructurer.
L'affectation de déstructuration permet de mapper instantanément un objet ou un tableau sur de nombreuses variables.
La syntaxe complète de l'objet :
let {prop : varName = defaultValue, ...rest} = objet
Cela signifie que la propriété prop
doit aller dans la variable varName
et, si aucune propriété de ce type n'existe, alors la valeur default
doit être utilisée.
Les propriétés d'objet qui n'ont pas de mappage sont copiées dans l'objet rest
.
La syntaxe du tableau complet :
laissez [item1 = defaultValue, item2, ...rest] = tableau
Le premier élément va à item1
; le second va dans item2
et tout le reste fait rest
le tableau.
Il est possible d'extraire des données de tableaux/objets imbriqués, pour cela le côté gauche doit avoir la même structure que celui de droite.
importance : 5
Nous avons un objet :
laissez l'utilisateur = { nom : "Jean", années : 30 } ;
Écrivez le devoir de déstructuration qui se lit comme suit :
propriété name
dans la variable name
.
years
de propriété dans l' age
variable.
propriété isAdmin
dans la variable isAdmin
(faux, s'il n'y a pas de propriété de ce type)
Voici un exemple des valeurs après votre mission :
let user = { nom : "John", années : 30 } ; // votre code à gauche : // ... = utilisateur alerte( nom ); // John alerte (âge); // 30 alerte( estAdmin ); // FAUX
laissez l'utilisateur = { nom : "Jean", années : 30 } ; let {nom, années : âge, isAdmin = false} = utilisateur ; alerte( nom ); // John alerte (âge); // 30 alerte( estAdmin ); // FAUX
importance : 5
Il existe un objet salaries
:
laissez les salaires = { "Jean": 100, "Pierre": 300, "Marie": 250 } ;
Créez la fonction topSalary(salaries)
qui renvoie le nom de la personne la mieux payée.
Si salaries
est vide, il doit renvoyer null
.
S'il y a plusieurs personnes les mieux payées, renvoyez-en une.
PS Utilisez Object.entries
et la déstructuration pour parcourir les paires clé/valeur.
Ouvrez un bac à sable avec des tests.
fonction topSalary(salaires) { laissez maxSalary = 0 ; laissez maxName = null; for(const [nom, salaire] de Object.entries(salaries)) { si (maxSalary < salaire) { maxSalary = salaire ; maxName = nom ; } } retourner maxName ; }
Ouvrez la solution avec des tests dans un bac à sable.