Clonar arreglos en JavaScript

En uno de mis artículos anteriores cubrí cómo puedes copiar objetos en JavaScript. Copiar un objeto es una tarea bastante complicada, dado que también tendrías que...

En uno de mis artículos anteriores cubrí cómo puedes copiar objetos en JavaScript. Copiar un objeto es una tarea bastante complicada, dado que también tendría que poder copiar cualquier otro tipo de datos que pudiera haber en el objeto. Pero, ¿qué sucede si solo está copiando una matriz? Al igual que el último artículo, hay bastantes formas de realizar esta tarea, algunas de las cuales repasaré en este artículo.

Pero primero, una nota sobre la velocidad. Si bien esto puede no ser importante para todas las aplicaciones, es algo a considerar si la copia de matrices grandes es una operación común en su código, o si la velocidad realmente importa. Para algunos de los métodos a continuación, observo su velocidad en relación con los otros métodos, que proviene de los resultados de [este punto de referencia] (http://jsben.ch/lO6C5).

Copiar arreglos simples

Para esta primera parte, supongamos que la matriz que desea copiar contiene solo tipos de datos primitivos (e inmutables). Es decir, la matriz solo contiene números, valores booleanos, cadenas, etc. De esta manera, podemos centrarnos más en la transferencia de datos de una matriz a otra, en lugar de cómo manejamos la copia del contenido real de la matriz, que es lo que hago. Lo cubriré en la sección "Copias profundas" a continuación.

Hay una cantidad sorprendente de formas de copiar una matriz, algunas de las cuales incluyen:

  • ’empujar'
  • Untado
  • rebanada
  • Array.from
  • _.clonar

El operador de propagación y el método slice son las formas más rápidas de copiar una matriz poco profunda, pero tenga en cuenta que esto depende del tiempo de ejecución subyacente, por lo que podría no ser universalmente cierto.

Empujar

Esta es probablemente la solución más obvia, que recorre la matriz original y usa el método push() de la nueva matriz para agregar elementos de una matriz a otra:

1
2
3
4
5
let oldArr = [3, 1, 5, 2, 9];
let newArr = [];
for (let i=0; i < oldArr.length; i++) {
    newArr.push(oldArr[i]);
}

Simplemente hacemos un bucle sobre la matriz que se va a copiar y empujamos cada elemento a la nueva matriz.

Untado

Este método utiliza el operador de propagación, que se definió en ES6 y está disponible en la mayoría de los -navegadores de fecha.

Funciona de la siguiente manera:

1
2
let oldArr = [3, 1, 5, 2, 9];
let newArr = [...oldArr];

Si voy a usar una solución nativa y no una biblioteca de terceros, esta suele ser la solución que prefiero gracias a su sintaxis limpia y simple.

Una nota importante es que esta copia solo funciona en el nivel superior (como muchos de estos métodos), por lo que no debe usarse si necesita copias profundas de cualquier cosa.

Rodaja

El método slice() generalmente se usa para devolver una parte de una matriz, especificada por los parámetros beginning y end. Sin embargo, si no se pasan parámetros, se devuelve una copia de toda la matriz:

1
2
let oldArr = [3, 1, 5, 2, 9];
let newArr = oldArr.slice();

En muchos tiempos de ejecución de JavaScript, esta es la forma más rápida de copiar una matriz.

Matriz.desde

El método Array.from está destinado a crear una copia superficial de cualquier iterable que le pases, y también toma una función de mapeo opcional como segundo parámetro. Por lo tanto, se puede usar para crear una matriz a partir de cadenas, conjuntos, mapas y, por supuesto, otras matrices:

1
2
let oldArr = [3, 1, 5, 2, 9];
let newArr = Array.from(oldArr);

Clon de Lodash

Los métodos clon() y clonProfundo() de Lodash Puede que te resulte familiar si lees Este artículo sobre la copia de objetos. Los métodos hacen exactamente lo que esperas: cualquier objeto (o matriz, primitivo, etc.) que se le pase será copiado y devuelto.

_.cloneDeep (que se describe más adelante) es diferente porque no deja de clonar en el nivel superior, sino que copia recursivamente todos los objetos que encuentra en cualquier nivel.

Dado esto, también podemos usarlo para copiar matrices:

1
2
let oldArr = [3, 1, 5, 2, 9];
let newArr = _.clone(oldArr);

_.clone funciona muy bien en comparación con los otros métodos, por lo que si ya está utilizando esta biblioteca en su aplicación, esta es una solución simple.

Copias profundas {#copias profundas}

Una cosa importante a señalar es que todos los métodos descritos anteriormente solo realizan copias superficiales de sus arreglos. Entonces, si tiene una matriz de objetos, por ejemplo, la matriz real se copiará, pero los objetos subyacentes se pasarán por referencia a la nueva matriz.

Para demostrar este problema, veamos un ejemplo:

1
2
3
4
let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let newArr = [...oldArr];
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
1
2
false
true

Aquí puede ver que si bien la matriz real es nueva, los objetos dentro de ella no lo eran. Para algunas aplicaciones esto puede ser un gran problema. Si esto se aplica a usted, aquí hay algunos otros métodos para probar.

Lodash Clon Deep

El método _.cloneDeep de Lodash hace exactamente lo mismo que _.clone(), excepto que clona recursivamente todo en la matriz (u objeto) que le pasas. Usando el mismo ejemplo anterior, podemos ver que usar _.cloneDeep() nos proporcionará tanto una nueva matriz * como * elementos de matriz copiados:

1
2
3
4
5
6
const _ = require('lodash');

let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let newArr = _.cloneDeep(oldArr);
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
1
2
false
false

Métodos JSON

JavaScript proporciona algunos métodos JSON útiles que manejan la conversión de la mayoría de los tipos de datos JS en una cadena y, luego, una cadena JSON válida en un objeto JS. Los métodos respectivos se utilizan de la siguiente manera:

1
2
3
4
5
6
7
8
9
let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let arrStr = JSON.stringify(oldArr);
console.log(arrStr);

let newArr = JSON.parse(arrStr);
console.log(newArr);

console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
1
2
3
4
'[{"foo":"bar"},{"baz":"qux"}]'
[ { foo: 'bar' }, { baz: 'qux' } ]
false
false

Este método funciona muy bien y no requiere bibliotecas de terceros. Sin embargo, hay dos cuestiones principales:

  • Los datos deben ser serializables y deserializables a través de JSON
  • Usar los métodos JSON de esta manera es mucho más lento que otras soluciones

Entonces, si tiene datos que no se pueden serializar en JSON o si la velocidad es importante para su aplicación, entonces esta podría no ser una buena solución para usted.

Conclusión

En este artículo, cubrí varias formas en que puede copiar matrices en JavaScript, tanto con código nativo como con una útil biblioteca de terceros en Lodash. También analizamos el problema de las matrices de clonación profunda y las soluciones que existen para resolverlo.

¿Hay algún método diferente que funcione mejor para ti? Háganos saber lo que piensa en los comentarios.