L’opérateur spread en JavaScript va vous simplifier la vie

August 01, 2019 -5 min de lecture

Javascript
ES6

Photo by Ray Hennessy on Unsplash

Les développeurs aiment se simplifier la vie n’est-ce pas ? Une légende urbaine dit même qu’ils sont fainéants. Afin d’honorer ce mythe, je vais vous montrer une nouvelle façon de simplifier votre code. Vous connaissez les points de suspension du langage courant ? Figurez vous qu’ils existent également en JavaScript et leur fonction va nous permettre de devenir se simplifier la vie. Royal n’est-ce pas ?

Le spread operator pour copier des variables

Le spread operator, qui se présente ni plus ni moins sous la forme de points de suspension : ... permet de faire des copies de variables en un tour de main.

const originale = "Pringles";
const copie = ...originale;
console.log(copie);
//affiche "Pringles"

Simple et efficace pour copier une variable. Ici je dis bien copier, c’est-à-dire que la variable d’origine et sa copie sont totalement indépendantes. Nous pouvons sans problème modifier l’une sans pour autant modifier l’autre. Si nous avions simplement utilisé le symbole =, la variable n’aurait pas été copiée :

const originale = "Pringles"
const reference = originale
console.log(reference)
//affiche "Pringles"

Cette façon de faire qui pourrait pourtant sembler naturelle créée en réalité non pas une copie, mais une référence à la variable d’origine. C’est-à-dire qu’en cas de modification d’une valeur dans la pseudo-copie, elle sera immédiatement répercutée sur la variable à laquelle elle fait référence.

Le spread operator pour copier un array

Ici, rien de bien compliqué. Le spread operator permet de copier avec cette même simplicité déconcertante des arrays de toute taille.

const array = ["jambon", "emmental", "cornichons", "pain", "beurre"]
const arrayCopie = [...array]

//affiche ['jambon', 'emmental', 'cornichons', 'pain', 'beurre']

Notez bien l’utilisation des crochets pour encadrer l’expression, c’est primordial lorsque vous copiez un array. Car n’oublions pas que la copie est un nouvel array dont le contenu est rempli par le spread operator, entrée après entrée. Nous devons toujours créer le contenant avant d’y insérer du contenu.

Que se passe-t-il si vous oubliez ces crochets ? Un joli message d’erreur va apparaître dans la console ! Uncaught SyntaxError: Unexpected token ....

Spread operator pour créer un array

Voilà une petite astuce qui pourrait s’avérer utile. Admettons que vous receviez une chaine de caractères via un formulaire. Vous voulez pouvoir analyser chaque caractère pour savoir s’il contient un caractère en particulier. Pour réaliser cette opération anodine, vous devez d’abord transformer votre chaine de caractère en array. Rien de plus simple avec le spread operator :

var string = "geek"
var array = [...string]
console.log(array)
// ['g', 'e',' e',' k']

Et voilà, la chaine de caractère a été copiée et transformée en array.

Spread operator pour la concaténation d’array

Il est parfois nécessaire de combiner plusieurs array en un seul. Imaginez par exemple que vous avez dressé une liste de pizzas en base crème et une autre de celle en base tomates.

Vous voudrez peut-être afficher la liste de toutes les pizzas sans considération de leur catégorie. Pour se faire, il est souvent utile de faire une concaténation d’array, c’est à dire rassembler plusieurs arrays en un seul.

const pizzas = [...pizzasCreme, "Pizza Ninja", ...pizzaTomate]
console.log(pizzas)

Oulala attendez c’est quoi cette Pizza Ninja au milieu ? Et bien c’est simplement une pizza qui ne faisait partie d’aucune liste et que nous avons rajoutée directement dans le nouvel array. Cette Pizza Ninja sera donc insérée entre les pizzas des deux array qui l’encadrent. J’aurais pu tout aussi bien placer cette instruction au début ou en fin d’arrêt. J’ai simplement trouvé que le milieu serait plus poétique. Plutôt pratique n’est-ce pas ?

La copie d’objets en JavaScript avec le spread operator

Il est tentant d’utiliser cette méthode pour copier un objet n’est-ce pas ? Vous pouvez tout à fait. Cependant il y a un détail majeur à prendre en considération. Maintenant que j’ai teasé, place à l’exemple d’une liste de pizzas disponibles chez Dominos Pizza (il ne s’agit pas d’un placement de produit, j’aurais pu choisir Pizza Hutt mais je préfère Dominos).

const dominos = {
  baconGroovy: {
    garniture: [
      "Crème fraîche légère",
      "mozzarella",
      "poulet rôti",
      "oignons",
      "bacon",
      "sauce barbecue",
    ],
    prix: {
      small: "6.00",
      medium: "8.00",
      large: "10.00",
    },
  },
  fromages: {
    garniture: [
      "Sauce tomate",
      "mozzarella",
      "chèvre",
      "Emmental",
      "Fourme d’Ambert A.O.P.",
    ],
    prix: {
      small: "6.50",
      medium: "7.50",
      large: "8.50",
    },
  },
}

const pizzasCopie = { ...dominos }

Voyons ce que cela donne dans la console.

let pizza = pizzasCopie.baconGroovy.prix.medium

console.log(pizza)
//affiche 8.00.

//Essayons maintenant de modifier le prix
pizza = 9.0
console.log(pizza)
//affiche 9.00. Tout va bien non ?

En apparence, tout fonctionne à merveille, seulement voilà, la copie qui vient d’être faite n’est pas complète, il s’agit en réalité d’une copie superficielle (shallow copy). Dans un langage plus courant, seuls les premiers niveaux sont véritablement copiés (ici baconGroovy et fromages). Les niveaux plus imbriqués (garniture et prix ne sont pas copiés, mais sont stockés sous forme de référence (donc sous la forme const b = a).

Regardons ce qu’il se passe dans la console dans l’objet d’origine.

console.log(pizzas.baconGroovy.prix.medium)
//affiche 9.00

Aïe ! En modifiant la valeur du paramètre imbriqué prix dans pizzasCopienous avons aussi modifié sa valeur d’origine dans dominos ! Ce n’est pas vraiment ce que nous attendions n’est-ce pas ? Mais c’est le comportement normal d’une référence comme nous avons pu le voir.

L’usage du spread avec un objet mêle donc les deux mondes : copie et référence selon le niveau d’imbrication des propriétés de l’objet.

Comment contourner ce problème ?

Si ce fonctionnement s’avère être un problème pour vous, sachez qu’il est possible d’utiliser une parade. La méthode que je vais vous montrer vous permettra d’effectuer ce que nous appelons couramment un deep clone. C’est un clone profond qui n’est pas superficiel contrairement à son homologue spread operator.

const pizzasCopie = JSON.parse(JSON.stringify(dominos))

En utilisant cette méthode, vous aurez la possibilité de modifier les propriétés de la copie sans craindre de changer les valeurs de l’objet original.

Une dernière chose sur la copie d’objet.

Copier votre objet de cette manière ne va copier que les paramètres (variables) de votre fonction. En aucun cas ses méthodes (fonctions). Si vous avez besoin de copier également les méthodes que vous avez définies, vous devrez utilisez à la place Object.assign. Je vous montre comment ça marche.

let pizzasCopie = Object.assign({}, dominos)

Vous aurez ainsi TOUT ce que contient votre objet. Paramètres et méthodes. Tadaaa.

C’est tout … pour le moment !


Mathias OVIEVE

Rédigé par moi : Mathias OVIEVE, développeur web et mobile fan de JavaScript sous toutes ses formes, mais aussi de Swift. Sectaire en rien, passionné en tout. Éternel apprenant et ravi de l’être.