Décomposition et déstructuration en Javascript

La décomposition et la déstructuration sont deux termes spécifiques pour exprimer la même chose. La décomposition s’applique aux tableaux et la déstructuration aux objets.

Maintenant que nous avons cerné les différences de nommage, le terme décomposition étant le seul retenu dans les RFCs et autres spécifications d’Ecma International, nous n’utiliserons plus que celui-ci dans le reste de cet article.

La décomposition consiste à "décomposer" les structures complexes (tableau, objet) pour en extraire les valeurs qui nous intéressent. L’intérêt est de rendre ce genre de manipulation plus simple et le code plus lisible.

let [ valeur1, valeur2 ] = tableau
let { valeur1, valeur2 } = objet

La syntaxe est différente s’il s’agit d’un tableau ou d’un objet.

Décomposer des tableaux

Un cas concret de décomposition des tableaux est lorsque nous souhaitons récupérer les valeurs d’un tableau.

let args = ['fruits', 'pomme', 'poire', 'abricot']
let type = args[0]
let firstEl = args[1]
let secondEl = args[2]
let thirdEl = args[3]

Sans décomposition voici comment on récupère des valeurs d’un tableau pour pouvoir les utiliser.

let args = ['fruits', 'pomme', 'poire', 'abricot']
let [type, firstEl, secondEl, thirdEl] = args

La même chose avec la décomposition.

Les deux codes sont similaires, le résultat est le même. Dans les deux cas les variables type, firstEl, secondEl, thirdEl sont créées.

Si nous nous arrêtons là, cette syntaxe n’a pas trop d’intérêt si ce n’est peut-être nous faire économiser trois lignes. Mais la décomposition vous réserve bien d'autres surprises qui vous feront gagner beaucoup de temps.

Nous ne comparerons pas à chaque fois avec des exemples sans décomposition, mais essayez de réfléchir à comment vous coderiez la même fonctionnalité sans décomposition.

Cas : Si je ne veux récupérer que le type et le second élément.

let args = ['fruits', 'pomme', 'poire', 'abricot']
let [type,, secondEl] = args

Il suffit d’ajouter une virgule entre args[0] et args[2] mais sans préciser de nom de variable dans laquelle mettre args[1].

Cas : Si args est vide mes variables type et secondEl seront créées, mais auront pour valeur undefined. Pour pouvoir continuer à travailler avec, il faudrait que je teste mes variables. Mais je peux aussi leur attribuer des valeurs par défaut.

let args = []
let [type = 'legume', firstEl = 'salade'] = args

Comme args est vide, type vaudra "légume" et firstEl vaudra "salade".

Cas : Si je veux récupérer le type de mes éléments dans une variable, mais qu’il est plus pratique pour moi que la liste des éléments soient dans un tableau pour pouvoir boucler dessus.

let args = ['fruits', 'pomme', 'poire', 'abricot']
let [type, ...elements] = args

Ici type vaudra "fruits" et elements vaudra ['pomme', 'poire', 'abricot'].

La syntaxe ici est assez particulière, car elle utilise ce que l’on appelle un paramètre du reste. Si vous souhaitez en savoir plus sur les paramètres du reste, lisez cet article.

On peut aussi utiliser la décomposition pour des cas auxquels on ne pense pas forcément :

Cas : Si je veux intervertir les valeurs de deux variables.

let valA = 'coucou'
let valB = 'byebye'
[valA, valB] = [valB, valA]

Logiquement valA vaudra "byebye" et valB vaudra "coucou".

Cas : La décomposition peut-être utilisée pour travailler avec des fonctions qui retournent des tableaux.

let [max, min] = getMaxAndMin([3, 34, 2, 5, 6, 22, 33, 1])

L’intérêt ici est encore la lisibilité du code. Il faudra évidement être sûr de l'ordre des valeurs retournées par la fonction utilisée.

Cas : Il est possible d’utiliser la décomposition en paramètre de fonction.

function firstIsTrue([ first = false ]) {
  return first === true
}

firstIsTrue() prend en paramètre un tableau. Seule la première valeur sera transmise à la fonction et si le tableau est vide first vaudra false.

Pour l’utilisateur de la fonction tout est transparent.

Décomposer des objets

La décomposition des objets est relativement la même que celle des tableaux avec quelques spécificités. Nous allons donc passer dessus un peu plus vite pour ne voir que les notions intéressantes.

Cas : Récupération d’une des clés

let objet = {
  slug: 'test'
  title: 'Ceci est un test'
  content: '...'
  visible: true
}

let { title } = objet

Exemple de base où on ne veut que le titre. Vous noterez l’utilisation des accolades à la place des crochets lorsqu’il s’agit d’objet.

Cas : Valeur par défaut

let objet = {
  slug: 'test'
  title: 'Ceci est un test'
  content: '...'
  visible: true
}

let { visible = false } = objet

On ne veut que la visibilité et qu’elle soit par défaut à false.

Cas : Utilisation d’un autre nom pour une clé

let objet = {
  slug: 'test'
  title: 'Ceci est un test'
  content: '...'
  visible: true
}

let { content: article } = objet

Ici, nous récupérons uniquement la clé content que nous stockons dans la variable article.

La vraie syntaxe de la décomposition est celle utilisée dans cet exemple. Dans les autres exemples nous utilisons une astuce de ES2015 qui nous évite d'écrire deux fois la même chose quand c’est possible. Retenez juste que { visible: visible } est égale à { visible }.

Cas : Cumul de la valeur par défaut et du changement de nom

let objet = {
  slug: 'test'
  title: 'Ceci est un test'
  content: '...'
  visible: true
}

let { visible: isVisible = false } = objet

Nous récupérons la clé visible que nous stockons dans la variable isVisible. Cette variable vaudra par défaut false.

Cas : Utilisation de la décomposition en paramètre de fonction

Il s’agit clairement du cas qui me pousse le plus à utiliser la décomposition. C’est un gain de temps impressionnant.

Vous avez surement déjà écrit des fonctions avec un paramètre options qui rassemble toutes vos options dans un objet. Pensez au temps que vous avez perdu et au nombre de lignes que vous avez écrit pour tester ce seul paramètre avant même de coder du métier.

function test(id, { maxLength = 10, current = 0 } = {})

Comme pour la décomposition de tableau, le fait de l’utiliser dans les paramètres d’une fonction est totalement transparent pour l’utilisateur, mais pour vous ça change tout.

maxLength et current ne seront jamais undefined, auront toujours une valeur que ce soit celle de l’utilisateur ou la valeur par défaut. Et ça allégera votre code vu que vous ne ferez plus options.maxLength mais juste maxLength comme s’il s’agissait d’un simple paramètre comme id.

Seul les attributs que vous avez déclarés dans la décomposition seront transmit à votre fonction. L’utilisateur peut bien ajouter 15 000 autres attributs à options ils ne seront pas transmis. Ce qui ajoute un léger niveau de sécurité à votre fonction.

Conclusion

J’espère sincèrement que vous avez été convaincu. La décomposition est, pour moi, une des plus grosses nouveautés de ES2015.

Une fonctionnalité puissante à utiliser sans modération pour rendre votre code plus simple, clair, concis, beau, propre, etc. Et vous savez à quel point j’aime le code propre.

Pour aller plus loin :