hand Inicio

SERVICIOS

Salir

nochedรญa

DESARROLLO WEB con
GATSBY y WORDPRESS

emoji Cursos [24]
emoji Themes Gatsby [5]
emoji Themes WordPress [2]
emoji Blog [83]
emoji Herramientas [11]

Cรณmo copiar un array en JavaScript?

700 palabras
3 minutos
July 1, 2020
blogjavascript

Te explico cรณmo copiar arrays en JavaScript y por quรฉ no es tan sencillo como parece

  1. Todo por referencia (o era valor?)
  2. Copiando el array, copia simple
  3. Copia shallow con Array.from o el spread operator
  4. Copia deep
  5. Copia deep con JSON

Todo por referencia (o era valor?)

Al igual que vimos con objects en cรณmo copiar un object, clonar arrays no es trivial ya que en JavaScript todo se copia por referencia

Quรฉ es copiar por referencia?

En JS cuando se copia un valor que NO es primitivo, en lugar de copiar el contenido de ese valor se copia una referencia a ese contenido

El sรญmil serรญa que si quieres copiar el museo Picasso, en lugar de copiar todo el edificio te limitarรญas a copiar la direcciรณn de dรณnde estรก ese edificio

Pero quรฉ es un valor primitivo?

A efectos prรกcticos, es un string, un number o un boolean

Es decir

  • cuando copiamos un string estamos copiando el valor
  • pero cuando copiamos un array de strings estamos copiando la direcciรณn de ese array, la referencia

Dicho esto, cuando se quiere clonar una variable lo que se quiere es hacer una copia por valor y no por referencia

Y no es trivial

*si quieres entretenerte, aquรญ tienes la pregunta del millรณn en stack overflow

Una manera prรกctica de verlo es con el uso de const

(const y let son los sustitutos de var en ES6)

Cualquier variable que se defina con const es una variable que no podrรก cambiarse (nos darรญa error)

js
const mistring = 'hola'
mistring = 'hola otra vez' // ERROR, la variable mistring ya ha sido definida y es una constante!!

Esto falla porque estamos asignando un nuevo valor a la misma variable que ya se ha definido antes como constante

En cambio, sรญ podemos hacer esto

js
const miarray = []
miarray[0] = 'hola'
miarray[0] = 'hola otra vez'
console.log(miarray) // ["hola otra vez"]

El valor de miarray es constante y no contiene un valor primitivo sino una referencia al objeto de tipo array

Podemos cambiar los valores del array, pero el objeto continuarรก siendo el mismo

Entonces, cuรกl es el problema con clonar arrays?

El problema estรก en que cuando copiamos una variable tendemos a esperar que en realidad se haya copiado toda la variable como si รฉsta fuera primitiva

En cรณdigo, estarรญamos esperando esto

js
const miarray = []
miarray[0] = 'hola'
const miarray2 = miarray
miarray2[0] = 'hola otra vez'
console.log(miarray) // ["hola"] FALSO, ESTO NO OCURRE
console.log(miarray2) // ["hola otra vez"]

Pero esto no es lo que pasa, de ahรญ el problema de clonar arrays

Copiando el array, copia simple

La copia simple simplemente copia la referencia del array, no nos sirve si lo que queremos es clonar ese array

js
const myArr = ['๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž']
const myCopy = myArr
myArr[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
console.log(myArr) // ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]
console.log(myCopy) // ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]
Ver en CodeSandBox

Copia shallow con Array.from o el spread operator

Una copia shallow de arrays se refiere a copiar la primera "capa" o dimensiรณn del array

Se puede hacer con un Array.from() o con el spread operator, que lo que hace es "desplegarnos" la estructura de datos

js
const myArr = [
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž', // una dimensiรณn
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž', // una dimensiรณn
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž', // una dimensiรณn
['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„', '๐ŸŒ›๐ŸŒ›๐ŸŒ›๐ŸŒ›'], // dos dimensiones
{ myOtherArray: ['๐Ÿค˜๐Ÿพ๐Ÿค˜๐Ÿพ๐Ÿค˜๐Ÿพ๐Ÿค˜๐Ÿพ'] }, // tres dimensiones
]
const myCopy = myArr
const myShallowCopy = Array.from(myArr) // con el Array.from
const myShallowCopy2 = [...myArr] // con el spread operator
// ahora cambio las variables del objeto original
myArr[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[1] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[3][0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[3][1] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[4].myOtherArray[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
// el array original y la copia simple
console.log(myArr) // ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myCopy) // ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
// Las copias shallow, que sรณlo aplican a la primera dimensiรณn
console.log(myShallowCopy) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", "๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", "๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myShallowCopy2) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", "๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", "๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", "๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
Ver en CodeSandBox

Puedes ver como sรญ que conseguimos clonar la primera dimensiรณn del array, pero que las otras dimensiones siguen siendo referencias al array original con lo que si cambiamos el original, tambiรฉn cambiamos la copia

Copia deep

Si una copia shallow era "superficial", una copia deep busca hacer una copia completa de todo el array

Y para hacerlo tenemos distintas maneras:

  • De forma manual con un loop que nos itere por todos los lados

  • Utilizando alguna librerรญa ultra-famosa como lodash

Vamos a ver los dos mรฉtodos, el primero (el manual) utilizando la soluciรณn de samanthaming, y el segundo con la librerรญa lodash

(si vas al codesandbox tendrรกs que aรฑadir la dependencia de lodash)

js
// importo lodash
import _ from 'lodash'
// funciรณn manual para clonar arrays
const clone = items => items.map(item => (Array.isArray(item) ? clone(item) : item))
// el array original
const myArr = ['๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž', ['๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž'], { myOtherArray: ['๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž'] }]
// copia shallow
const myShallowCopy = [...myArr]
// copia deep manual
const myDeepCopy = clone(myArr)
// copia deep con los dos mรฉtodos de lodash, uno para shallow y otro para deep
const myShallowLodashClone = _.clone(myArr)
const myDeepLodashClone = _.cloneDeep(myArr)
// cambio el array original
myArr[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[1][0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[2].myOtherArray[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
// Y a ver quรฉ nos dan los clones
console.log(myArr) // ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myShallowCopy) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myDeepCopy) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myShallowLodashClone) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myDeepLodashClone) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž"], {myOtherArray: ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž"]}]
Ver en CodeSandBox

Puedes ver cรณmo las copias shallow sรณlo copian la primera dimensiรณn

Pero tambiรฉn puedes ver cรณmo la funciรณn manual que he utilizado no consigue copiar el objeto que estรก dentro de la estructura

Para que tambiรฉn copiase objetos tendrรญamos que modificar la funciรณn

  • Puedes hacerla tu mismo
  • Puedes utilizar la funciรณn de lodash, y si sรณlo quieres esa funciรณn puedes utilizar esa รบnica librarรญa en lodash.clonedeep
  • O puedes mirar esa misma librerรญa y explorar su cรณdigo para hacerte tu propia versiรณn del tema

Copia deep con JSON

Otro mรฉtodo tremendamente prรกctico y que no requiere de librerรญas externas es el mรฉtodo JSON

Se trata de convertir nuestro array en un objeto JSON, y luego volver a convertir ese objeto en un nuevo array

Haciendo esto, lo que estamos haciendo en realidad es un deep clone del array

js
const myArr = ['๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž', ['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'], { myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] }]
const myJSONCopy = JSON.parse(JSON.stringify(myArr))
myArr[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
myArr[1] = ['๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ']
myArr[2].myOtherArray[0] = '๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ'
console.log(myArr) // ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ", ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"], {myOtherArray: ["๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ"]}]
console.log(myJSONCopy) // ["๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž", ["๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ"], {myOtherArray: ["๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„"]}]
Ver en CodeSandBox
  • Ventajas? Se lee muy fรกcilmente y no dependes de una librerรญa externa
  • Desventajas? Cierta incompatibilidad con algunos tipos de datos (como Date)

En cuanto a velocidad, haciendo un benchmark con measurethat.net vemos lo siguiente:

  • Con estructuras sencillas, la soluciรณn con lodash es un 1.5x mรกs rรกpida que la soluciรณn con JSON
  • Con estructuras "algo" complejas como la que verรกs debajo, la soluciรณn JSON ya empieza a ir mรกs rรกpido que la de lodash
js
const myArr = [
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'] },
]

Ojo, en ninguno de los dos casos conseguiremos copiar mรฉtodos

js
const myArr = [
'๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž',
['๐Ÿฅ๐Ÿฅ๐Ÿฅ๐Ÿฅ'],
{ myOtherArray: ['๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„๐Ÿฆ„'], myMethod: () => console.log('hola como estamos') },
]

En la copia, ese mรฉtodo se habrรก perdido

๐Ÿ™‹โ€โ™‚๏ธ

Quรฉ tal la entrada?
๐Ÿ‘Œ Bien ๐Ÿ™Œ๐Ÿ™Œ
๐Ÿ‘ Bien, pero algunas cosas podrรญan explicarse mejor ๐Ÿ˜ฌ
๐Ÿคทโ€โ™‚๏ธ Da por sentadas demasiadas cosas ๐Ÿ˜’
๐Ÿคทโ€โ™‚๏ธ A ver, hay poca chicha ๐Ÿ˜ฌ
๐Ÿคทโ€โ™‚๏ธ Los ejemplos no son muy claros ๐Ÿ™‡โ€โ™‚๏ธ
๐Ÿคทโ€โ™‚๏ธ No se entiende, estรก mal escrito ๐Ÿ‘Ž
โœ๏ธ Hay errores, revรญsalo en cuanto puedas ๐Ÿ™

Mรกs entradas

Privacidad
by kuworking.com
[ 2020 >> kuworking ]