Al copiar una matriz en JavaScript a otra matriz:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
Me di cuenta de que se arr2
refiere a la misma matriz que arr1
, en lugar de una nueva matriz independiente. ¿Cómo puedo copiar la matriz para obtener dos matrices independientes?
javascript
arrays
Dan
fuente
fuente
slice
ysplice
operaciones geniales y un nuevo operador extendido yArray.from
tenemos una implementación mucho más lenta. Mira perfjs.fnfovar arr2 = arr1.splice();
para copia profunda, pero esta técnica no funcionará si los elementos en la matriz contener estructuras literales (es decir,[]
o{}
) o prototipos de objetos (es decirfunction () {}
,new
, etc). Vea mi respuesta a continuación para obtener más soluciones.let arr2 = [...arr1];
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Respuestas:
Utilizar este:
Básicamente, la
slice()
operación clona la matriz y devuelve una referencia a una nueva matriz.También tenga en cuenta que:
Para referencias, cadenas y números (y no el objeto real),
slice()
copia referencias de objetos en la nueva matriz. Tanto la matriz original como la nueva se refieren al mismo objeto. Si un objeto al que se hace referencia cambia, los cambios son visibles tanto para las matrices nuevas como para las originales.Las primitivas como cadenas y números son inmutables, por lo que los cambios en la cadena o el número son imposibles.
fuente
.slice()
con.splice()
, lo que le da una matriz vacía. Gran diferencia.En Javascript, las técnicas de copia profunda dependen de los elementos de una matriz. Comencemos por ahí.
Tres tipos de elementos
Los elementos pueden ser: valores literales, estructuras literales o prototipos.
A partir de estos elementos podemos crear tres tipos de matrices.
Las técnicas de copia profunda dependen de los tres tipos de matriz
Según los tipos de elementos en la matriz, podemos usar varias técnicas para copiar en profundidad.
Matriz de valores literales (tipo1)
El
[...myArray]
,myArray.splice(0)
,myArray.slice()
, ymyArray.concat()
técnicas pueden ser utilizadas para arrays copia profunda con valores literales (boolean, el número y cuerda) sólo; donde el operador Spread[...myArray]
tiene el mejor rendimiento ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).Matriz de valores literales (tipo1) y estructuras literales (tipo2)
La
JSON.parse(JSON.stringify(myArray))
técnica se puede utilizar para copiar en profundidad valores literales (booleanos, números, cadenas) y estructuras literales (matriz, objeto), pero no prototipos de objetos.Todas las matrices (tipo1, tipo2, tipo3)
La
$.extend(myArray)
técnica jQuery se puede utilizar para copiar en profundidad todos los tipos de matriz. Las bibliotecas como Underscore y Lo-dash ofrecen funciones de copia profunda similares a jQuery$.extend()
, pero tienen un rendimiento más bajo. Más sorprendentemente,$.extend()
tiene un rendimiento más alto que laJSON.parse(JSON.stringify(myArray))
técnica http://jsperf.com/js-deep-copy/15 .Y para aquellos desarrolladores que evitan las bibliotecas de terceros (como jQuery), puede usar la siguiente función personalizada; que tiene un rendimiento superior a $ .extend y copia en profundidad todas las matrices.
Entonces para responder la pregunta ...
Pregunta
Responder
Debido a que
arr1
es una matriz de valores literales (booleano, número o cadena), puede usar cualquier técnica de copia profunda descrita anteriormente, donde el operador de propagación...
tiene el rendimiento más alto.fuente
arr1
. Es muy raro que ese sea el caso. Usandosplice
borraarr1
, así que eso no es una copia en absoluto. El usoJSON
fallará si alguno de los valores de la matriz son Funciones o tienen prototipos (como aDate
).[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]
y cualquier otra matriz.Puede usar spreads de matriz
...
para copiar matrices.const itemsCopy = [...items];
Además, si desea crear una nueva matriz con la existente como parte de ella:
Los diferenciales de matriz ahora son compatibles con todos los principales navegadores, pero si necesita soporte anterior, use mecanografiado o babel y compílelo en ES5.
Más información sobre spreads
fuente
No se necesita jQuery ... Ejemplo de trabajo
Esto copia la matriz desde la posición inicial
0
hasta el final de la matriz.Es importante tener en cuenta que funcionará como se esperaba para los tipos primitivos (cadena, número, etc.), y también para explicar el comportamiento esperado para los tipos de referencia ...
Si tiene una matriz de tipos de referencia, digamos de tipo
Object
. La matriz se copiará, pero ambas matrices contendrán referencias a las mismasObject
. Entonces, en este caso, parecería que la matriz se copia por referencia aunque la matriz se copie realmente.fuente
var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
Una alternativa a
slice
esconcat
, que se puede utilizar de 2 maneras. El primero de ellos es quizás más legible ya que el comportamiento previsto es muy claro:El segundo método es:
Cohen (en los comentarios) señaló que este último método tiene un mejor rendimiento .
La forma en que esto funciona es que el
concat
método crea una nueva matriz que consta de los elementos en el objeto sobre el que se llama, seguido de los elementos de cualquier matriz que se le pase como argumento. Entonces, cuando no se pasan argumentos, simplemente copia la matriz.Lee Penkman, también en los comentarios, señala que si hay una posibilidad
array1
esundefined
, puede devolver una matriz vacía de la siguiente manera:O, para el segundo método:
Tenga en cuenta que también se puede hacer esto con
slice
:var array2 = (array1 || []).slice();
.fuente
[].concat(array1)
devuelve,[array1]
por ejemplo, si está indefinido, obtendrá[undefined]
. A veces lo hagovar array2 = [].concat(array1 || []);
Así es como lo hice después de probar muchos enfoques:
Esto creará una nueva copia profunda no relacionada con la primera (no una copia superficial).
Además, esto obviamente no clonará eventos y funciones, pero lo bueno es que puede hacerlo en una línea, y puede usarse para cualquier tipo de objeto (matrices, cadenas, números, objetos ...)
fuente
Date
, o de hecho, cualquier cosa que tenga un prototipo. Además,undefined
s se convierte ennull
s.Algunos de los métodos mencionados funcionan bien cuando se trabaja con tipos de datos simples como número o cadena, pero cuando la matriz contiene otros objetos, estos métodos fallan. Cuando intentamos pasar cualquier objeto de una matriz a otra, se pasa como referencia, no como el objeto.
Agregue el siguiente código en su archivo JavaScript:
Y simplemente usa
Funcionará.
fuente
.slice()
todavía funciona bien incluso si tiene objetos en su matriz: jsfiddle.net/edelman/k525gDesde ES2015,
fuente
Personalmente, creo que Array.from es una solución más legible. Por cierto, solo ten cuidado con el soporte de su navegador.
fuente
.slice()
solución es completamente intuitiva. Gracias por esto.¡Importante!
La mayoría de las respuestas aquí funcionan para casos particulares .
Si no te interesan los objetos profundos / anidados y el uso de accesorios ( ES6 ):
let clonedArray = [...array]
pero si quieres hacer un clon profundo usa esto en su lugar:
let cloneArray = JSON.parse(JSON.stringify(array))
Para usuarios lodash:
let clonedArray = _.clone(array)
documentacióny
let clonedArray = _.cloneDeep(array)
documentaciónfuente
Si se encuentra en un entorno de ECMAScript 6 , utilizando el Operador Spread puede hacerlo de esta manera:
fuente
Agregando a la solución de array.slice (); tenga en cuenta que si tiene una matriz multidimensional, las matrices secundarias se copiarán por referencias. Lo que puede hacer es hacer un bucle y cortar () cada sub-matriz individualmente
Lo mismo ocurre con la matriz de objetos, se copiarán por referencia, debe copiarlos manualmente
fuente
Los valores primitivos siempre se pasan por su valor (copiado). Sin embargo, los valores compuestos se pasan por referencia.
Entonces, ¿cómo copiamos este arr?
Copiar una matriz en ES6
Copiar n matriz en ES5
¿Por qué `let arrCopy = arr` no pasa por valor?
Pasar una variable a otra en valores compuestos como Object / Array se comportan de manera diferente. Usando el operador asign en los valores de copando, pasamos referencia a un objeto. Es por eso que el valor de ambas matrices está cambiando al eliminar / agregar elementos arr.
Excepciones:
Cuando asigna un nuevo valor a la variable, está cambiando la referencia misma y no afecta el objeto / matriz original.
Lee mas
fuente
Como sabemos en Javascript, las matrices y los objetos son por referencia, pero ¿de qué maneras podemos copiar la matriz sin cambiar la matriz original más adelante?
Aquí hay algunas formas de hacerlo:
Imagina que tenemos esta matriz en tu código:
1) Recorrer la matriz en una función y devolver una nueva matriz, como esta:
2) Usando el método de división, la división es para dividir parte de la matriz, dividirá parte de su matriz sin tocar el original, en la división, si no especifica el inicio y el final de la matriz, dividirá la totalidad matriz y básicamente hacer una copia completa de la matriz, para que podamos decir fácilmente:
3) También método de contacto, esto es para fusionar dos matrices, pero solo podemos especificar una de las matrices y luego básicamente hacer una copia de los valores en la nueva matriz contactada:
4) También se recomienda el método stringify y parse, no se recomienda, pero puede ser una forma fácil de copiar Array y Objetos:
5) Método Array.from, esto no es ampliamente compatible, antes del uso verifique el soporte en diferentes navegadores:
6) Modo ECMA6, tampoco totalmente compatible, pero babelJs puede ayudarlo si desea transpilar:
fuente
Ahora puede hacer cualquiera de los siguientes para hacer una copia de una matriz.
O
O
O
O
Ahora, si cambio un,
Entonces, a es [1,2,3,5] pero b sigue siendo [1,2,3] ya que tiene una referencia diferente.
Pero creo que, en todos los métodos anteriores, Array.from es mejor y está hecho principalmente para copiar una matriz.
fuente
Yo personalmente preferiría esta manera:
fuente
En mi caso particular, necesitaba asegurarme de que la matriz permaneciera intacta, así que esto funcionó para mí:
fuente
Haga una copia de la matriz / objeto multidimensional:
Gracias a James Padolsey por esta función.
Fuente: aquí
fuente
Dan, no necesitas usar trucos elegantes. Todo lo que necesita hacer es hacer una copia de arr1 haciendo esto.
Ahora
arr1
yarr2
hay dos variables de matriz diferentes almacenadas en pilas separadas. Mira esto en jsfiddle .fuente
var arr2 = [arr1];
).Cuando queremos copiar una matriz usando el operador de asignación (
=
), no crea una copia, simplemente copia el puntero / referencia a la matriz. Por ejemplo:A menudo, cuando transformamos datos, queremos mantener intacta nuestra estructura de datos inicial (por ejemplo, Array). Hacemos esto haciendo una copia exacta de nuestra matriz para que ésta pueda transformarse mientras la inicial permanece intacta.
Formas de copiar una matriz:
¡Tenga cuidado cuando las matrices u objetos estén anidados !:
Cuando las matrices están anidadas, los valores se copian por referencia. Aquí hay un ejemplo de cómo esto podría conducir a problemas:
Por lo tanto, no use estos métodos cuando haya objetos o matrices dentro de su matriz que desee copiar. es decir, utilice estos métodos solo en matrices de primitivas.
Si desea clonar en profundidad una matriz de javascript, use
JSON.parse
en conjunto conJSON.stringify
, de esta manera:Rendimiento de la copia:
Entonces, ¿cuál elegimos para un rendimiento óptimo? Resulta que el método más detallado, el
for
bucle tiene el mayor rendimiento. Use elfor
bucle para una copia realmente intensiva de la CPU (matrices grandes / múltiples)Después de eso, el
.slice()
método también tiene un rendimiento decente y es menos detallado y más fácil de implementar para el programador. Sugiero usar.slice()
para su copia diaria de arreglos que no requieren mucha CPU. También evite usarJSON.parse(JSON.stringify(arr))
(mucha sobrecarga) si no se requiere un clon profundo y el rendimiento es un problema.Prueba de rendimiento de origen
fuente
Si su matriz contiene elementos del tipo de datos primitivos , como int, char o string, etc. , puede usar uno de esos métodos que devuelve una copia de la matriz original, como .slice () o .map () u operador de propagación ( gracias a ES6).
o
o
PERO si su matriz contiene elementos complejos como objetos (o matrices) u más objetos anidados , entonces deberá asegurarse de hacer una copia de todos los elementos desde el nivel superior hasta el último nivel de referencia del interior. se usarán objetos y eso significa que el cambio de valores en object_elements en new_array seguirá afectando al old_array. Puede llamar a este método de copia en cada nivel como hacer una COPIA PROFUNDA de old_array.
Para la copia profunda, puede usar los métodos mencionados anteriormente para los tipos de datos primitivos en cada nivel, dependiendo del tipo de datos o puede usar este método costoso (mencionado a continuación) para hacer una copia profunda sin hacer mucho trabajo.
Existen muchos otros métodos que puede usar según sus requisitos. Solo he mencionado algunos de ellos para dar una idea general de lo que sucede cuando intentamos copiar una matriz en la otra por valor .
fuente
Si desea hacer una nueva copia de un objeto o matriz, debe copiar explícitamente las propiedades del objeto o los elementos de la matriz, por ejemplo:
Puede buscar más información en Google sobre valores primitivos inmutables y referencias de objetos mutables.
fuente
El uso de jQuery deep copy se puede hacer de la siguiente manera:
fuente
También puede usar el operador de propagación ES6 para copiar la matriz
fuente
Aquí hay algunas formas más de copiar:
fuente
Podrías usar ES6 con Opeartor extendido, es más simple.
Hay limitaciones ... verifique los documentos Sintaxis de propagación @ mozilla
fuente
Ejemplos rápidos:
fuente
Aquí hay una variante:
fuente
toSource
cuenta que no es estándar y no funcionará en Chrome, por ejemplo.Existe el recién presentado
Array.from
, pero desafortunadamente, a la fecha de este escrito solo es compatible con las versiones recientes de Firefox (32 y superiores). Se puede usar simplemente de la siguiente manera:Referencia: aquí
O
Array.prototype.map
puede usarse con una función de identidad:Referencia: aquí
fuente
Array.from
, que ahora es compatible con todos los principales navegadores, excepto Internet Explorer ( fuente ). .Array.from
que mutará los datos, no proporciona copia profunda / clonación profunda.Para la matriz ES6 que contiene objetos
fuente