Original article: How to clone an array in JavaScript

En JavaScript, il existe de nombreuses façons de faire les choses. J'ai écrit sur 10 façons d'écrire pipe/compose en JavaScript et maintenant nous allons nous attaquer aux tableaux.

1. Paramètres du reste (Copie superficielle)

Depuis la sortie d'ES6, c'est la méthode la plus populaire. C'est une syntaxe brève et vous la trouverez incroyablement utile lorsque vous utiliserez des librairies comme React et Redux.

numbers = [1, 2, 3];
numbersCopy = [...numbers];

Remarque : Cette méthode ne permet pas de copier en toute sécurité des tableaux multidimensionnels. Les valeurs des tableaux/objets sont copiées par référence et non par valeur.

Correcte

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers est resté intacte

Incorrecte

nestedNumbers = [[1], [2]];
numbersCopy = [...nestedNumbers];

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// Ils ont tous deux été changés parce qu'ils partagent des références

2. La bonne vieille boucle for() (Copie superficielle)

J'imagine que cette approche est la moins populaire, étant donné que la programmation fonctionnelle est devenue très à la mode dans nos milieux.

Pure ou impure, déclarative ou impérative, elle fait ce qu'on lui demande!

numbers = [1, 2, 3];
numbersCopy = [];

for (i = 0; i < numbers.length; i++) {
  numbersCopy[i] = numbers[i];
}

Remarque: Cette méthode ne permet pas de copier des tableaux multidimensionnels en toute sécurité. Comme vous utilisez l'opérateur = , les objets/tableaux seront assignés par référence et non par valeur.

Correcte

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers est resté intacte

Incorrecte

nestedNumbers = [[1], [2]];
numbersCopy = [];

for (i = 0; i < nestedNumbers.length; i++) {
  numbersCopy[i] = nestedNumbers[i];
}

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// Ils ont tous deux été changés parce qu'ils partagent des références

3. La bonne vieille boucle while() (Copie superficielle)

Comme pour for—impure, impérative, blah, blah, blah…ça fonctionne! ?

numbers = [1, 2, 3];
numbersCopy = [];
i = -1;

while (++i < numbers.length) {
  numbersCopy[i] = numbers[i];
}

Remarque: Cela permet également d'assigner des objets/tableaux par référence plutôt que par valeur.

Correcte

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers est resté intacte

Incorrecte

nestedNumbers = [[1], [2]];
numbersCopy = [];

i = -1;

while (++i < nestedNumbers.length) {
  numbersCopy[i] = nestedNumbers[i];
}

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// Ils ont tous deux été changés parce qu'ils partagent des références

4. Array.map (Copie superficielle)

Avec une approche un peu plus moderne, nous allons trouver la fonction map. Enraciné dans les mathématiques, map est le concept qui consiste à transformer un ensemble en un autre type d'ensemble, tout en conservant sa structure.

En Français, cela signifie que Array.map renvoie un tableau de longueur identique à chaque fois.

Pour doubler une liste de chiffres, utilisez map avec une fonction double.

numbers = [1, 2, 3];
double = (x) => x * 2;

numbers.map(double);

Qu'en est-il du clonage??

C'est exact, cet article traite du clonage des tableaux. Pour dupliquer un tableau, il suffit de retourner l'élément à l’intérieur de map.

numbers = [1, 2, 3];
numbersCopy = numbers.map((x) => x);

Si vous souhaitez une approche un peu plus mathématique, (x) => x est appelée identité. Cela renvoie quelque chose peu importe le paramètre qui lui a été donné.

map(identity) clone une liste.

identity = (x) => x;
numbers.map(identity);
// [1, 2, 3]

Remarque: Cela permet également d'assigner des objets/tableaux par référence plutôt que par valeur.

5. Array.filter (Copie superficielle)

Cette fonction renvoie un tableau, tout comme map, mais il n'est pas garanti que celui-ci soit de la même longueur.

Que faire si vous filtrez uniquement les nombres pairs ?

[1, 2, 3].filter((x) => x % 2 === 0);
// [2]

La longueur du tableau en entrée était de 3, mais la longueur qui en résulte est de 1.

Même si filterprévoyait de retourner true, vous obtenez un doublon!

numbers = [1, 2, 3];
numbersCopy = numbers.filter(() => true);

Chaque élément passe le test, ils sont donc tous renvoyés.

Remarque: Cela permet également d'assigner des objets/tableaux par référence plutôt que par valeur.

6. Array.reduce (Copie superficielle)

Je m'en veux un peu d'utiliser reduce pour cloner un tableau parce que c'est tellement plus puissant que ça. Mais c'est parti...

numbers = [1, 2, 3];

numbersCopy = numbers.reduce((newArray, element) => {
  newArray.push(element);

  return newArray;
}, []);

reduce transforme une valeur initiale en bouclant sur une liste.

Ici, la valeur initiale est un tableau vide et nous le remplissons avec chaque élément au fur et à mesure. Ce tableau doit être renvoyé par la fonction pour être utilisé lors de la prochaine itération.

Remarque: Cela permet également d'assigner des objets/tableaux par référence plutôt que par valeur.

7. Array.slice (Copie superficielle)

slice retourne une copie superficielle d'un tableau basé sur l'indice de début/fin que vous lui avez indiqué.

Si nous voulons les 3 premiers éléments:

[1, 2, 3, 4, 5].slice(0, 3);
// [1, 2, 3]
// Commence à l'index 0, se termine à l'index 3

Si on veut récupéré tous les éléments, il ne faut pas donner de paramètres.

numbers = [1, 2, 3, 4, 5];
numbersCopy = numbers.slice();
// [1, 2, 3, 4, 5]

Remarque: Il s'agit d'une copie superficielle, c'est-à-dire qu'elle affecte également les objets/tableaux par référence plutôt que par valeur.

8. JSON.parse et JSON.stringify (Copie profonde)

JSON.stringify transforme un objet en une chaîne de caractères.

JSON.parse transforme une chaîne de caractères en objet.

En les combinant, on peut transformer un objet en une chaîne de caractères, puis inverser le processus pour créer une toute nouvelle structure de données.

Remarque: Celui-ci copie en toute sécurité des objets/tableaux profondément imbriqués !

nestedNumbers = [[1], [2]];
numbersCopy = JSON.parse(JSON.stringify(nestedNumbers));

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);

// [[1], [2]]
// [[1, 300], [2]]
// Ces deux tableaux sont complètement séparés!

9. Array.concat (Copie superficielle)

concat combine des tableaux avec des valeurs ou d'autres tableaux.

[1, 2, 3].concat(4); // [1, 2, 3, 4]
[1, 2, 3].concat([4, 5]); // [1, 2, 3, 4, 5]

Si vous ne lui donnez rien ou alors un tableau vide, une copie superficielle est retournée.

[1, 2, 3].concat(); // [1, 2, 3]
[1, 2, 3].concat([]); // [1, 2, 3]

Remarque: Cela permet également d'assigner des objets/tableaux par référence plutôt que par valeur.

10. Array.from (Copie superficielle)

Ceci peut transformer n'importe quel objet itérable en un tableau. Lui donner un tableau retourne une copie superficielle.

numbers = [1, 2, 3];
numbersCopy = Array.from(numbers);
// [1, 2, 3]

Remarque: Cela permet également d'assigner des objets/tableaux par référence plutôt que par valeur.

Conclusion

Eh bien, c'était amusant ?

J'ai essayé de cloner en utilisant une seule étape à chaque fois. Vous trouverez beaucoup plus de façon de faire si vous utilisez plusieurs méthodes et techniques.