Articolo originale: How to clone an array in JavaScript di Yazeed Bzadough

Tradotto e adattato da: Angelo Mirabelli

JavaScript ha molti modi per fare qualsiasi cosa. Ho scritto 10 modi per scrivere pipe/compose in JavaScript e ora ci occuperemo degli array.

1. Operatore Spread  (copia poco profonda)

Da quando ES6 è stato rilasciato, questo è diventato il metodo più popolare. Ha una breve sintassi e la troverai incredibilmente utile quando userai librerie come React e Redux.

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

Nota: questo non copia in modo sicuro gli array multidimensionali. I valori di array/object vengono copiati per riferimento anziché per valore .

Questo va bene

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] e [1, 2, 3, 4]
// numbers è rimasto invariato

Questo non va bene

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

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// Entrambi sono stati modificati perché condividono i riferimenti

2. Il buon vecchio ciclo for() (copia poco profonda)

Immagino che questo approccio sia il meno popolare, vista la tendenza alla moda della programmazione funzionale nelle nostre cerchie.

Puro o impuro, dichiarativo o imperativo, fa il suo lavoro!

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

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

Nota: questo non copia in modo sicuro gli array multidimensionali. Poiché stai usando l'operatore =, assegnerà oggetti/matrici per riferimento anziché per valore .

Questo va bene

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers rimane invariato

Questo non va bene

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]]
// Entrambi sono stati modificati perché condividono i riferimenti

3. Il buon vecchio ciclo while() (copia poco profonda)

La stessa cosa di for — impuro, imperativo, bla, bla, bla… funziona! ?

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

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

Nota: anche questo assegna oggetti/array per riferimento invece che per valore .

Questo va bene

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers rimane invariato

Questo non va bene

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]]
// Entrambi sono stati modificati perché condividono i riferimenti

4. Array.map (copia poco profonda)

Tornando nel territorio moderno, troveremo la funzione map. Radicato nella matematica , map è il concetto di trasformare un insieme in un altro tipo di insieme, preservando la struttura.

Traducendo, ciò significa che Array.map restituisce ogni volta un array della stessa lunghezza.

Per raddoppiare un elenco di numeri, puoi utilizzare map con una funzione double.

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

numbers.map(double);

E la clonazione??

È vero, questo articolo riguarda la clonazione di array. Per duplicare un array, restituisci semplicemente l'elemento nella tua chiamata a map.

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

Se vuoi essere un po' più matematico, (x) => x si chiama identità . Restituisce qualsiasi parametro gli sia stato assegnato.

map(identity)clona una lista.

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

Nota: questo assegna anche oggetti/array per riferimento invece che per valore .

5. Array.filter (copia poco profonda)

Questa funzione restituisce un array, proprio come map, ma non è garantito che abbia la stessa lunghezza.

E se stai filtrando per numeri pari?

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

La lunghezza dell'array di input era 3, ma la lunghezza risultante è 1.

Tuttavia, se la funzione all'interno del tuo filter ritorna sempre true,  otterrai un duplicato!

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

Ogni elemento supera il test, quindi viene restituito.

Nota: anche questo assegna oggetti/array per riferimento invece che per valore .

6. Array.reduce (copia poco profonda)

Mi sento quasi male usando reduce per clonare un array, perché è molto più potente di questo. Ma eccoci qua...

numbers = [1, 2, 3];

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

  return newArray;
}, []);

reduce trasforma un valore iniziale mentre scorre un elenco.

Qui il valore iniziale è un array vuoto e lo stiamo riempiendo con ogni elemento mentre procediamo. Tale matrice deve essere restituita dalla funzione da utilizzare nell'iterazione successiva.

Nota: questo assegna anche oggetti/array per riferimento invece che per valore .

7. Array.slice (copia poco profonda)

slice restituisce una copia superficiale di un array in base all'indice di inizio/fine fornito dall'utente.

Se vogliamo i primi 3 elementi:

[1, 2, 3, 4, 5].slice(0, 3);
// [1, 2, 3]
// Inizia all'indice 0, fermati all'indice 3

Se vogliamo tutti gli elementi, non diamo alcun parametro

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

Nota: anche questa è una copia superficiale, quindi assegna oggetti/array per riferimento anziché per valore .

8. JSON.parse e JSON.stringify (copia profonda)

JSON.stringify trasforma un oggetto in una stringa.

JSON.parse trasforma una stringa in un oggetto.

La loro combinazione può trasformare un oggetto in una stringa e quindi invertire il processo per creare una struttura di dati nuova di zecca.

Nota: questo copia in modo sicuro oggetti/array profondamente nidificati !

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

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

// [[1], [2]]
// [[1, 300], [2]]
// Questi due array sono completamente separati!

9. Array.concat (copia poco profonda)

concat combina array con valori o altri array.

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

Se non fornisci nulla o un array vuoto, viene restituita una copia superficiale.

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

Nota: anche questo assegna oggetti/array per riferimento invece che per valore .

10. Array.from (copia poco profonda)

Questo può trasformare qualsiasi oggetto iterabile in un array. Fornendo un array restituisce una copia superficiale.

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

Nota: anche questo assegna oggetti/array per riferimento invece che per valore .

Conclusione

Bene, non è stato divertente?

Ho provato a clonare usando solo 1 passaggio. Troverai molti altri modi se utilizzi più metodi e tecniche.