Copiar matriz por valor

1745

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 arr2refiere a la misma matriz que arr1, en lugar de una nueva matriz independiente. ¿Cómo puedo copiar la matriz para obtener dos matrices independientes?

Dan
fuente
3
Parece que actualmente en Chrome 53 y Firefox 48 tenemos un rendimiento slicey spliceoperaciones geniales y un nuevo operador extendido y Array.fromtenemos una implementación mucho más lenta. Mira perfjs.fnfo
Pencroff
jsben.ch/#/wQ9RU <= este punto de referencia ofrece una visión general sobre las diferentes formas de copiar una matriz
EscapeNetscape
Para esta matriz (uno que contiene cadenas primitivas) que puede utilizar var 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 decir function () {}, new, etc). Vea mi respuesta a continuación para obtener más soluciones.
tfmontague
16
Es 2017, por lo que podría considerar usar las funciones de ES6: let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Hinrich

Respuestas:

2701

Utilizar este:

var newArray = oldArray.slice();

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.

Saket
fuente
99
Con respecto al rendimiento, las siguientes pruebas de jsPerf muestran que var arr2 = arr1.slice () es tan rápido como var arr2 = arr1.concat (); JSPerf: jsperf.com/copy-array-slice-vs-concat/5 y jsperf.com/copy-simple-array . El resultado de jsperf.com/array-copy/5 me sorprendió hasta el punto de que me pregunto si el código de prueba es válido.
Cohen
94
A pesar de que esto ya ha recibido un montón de votos a favor, merece otro porque describe adecuadamente las referencias en JS, lo cual es algo raro, desafortunadamente.
Wayne
34
@ GáborImre ¿agregaría una biblioteca completa simplemente para facilitar la lectura? De Verdad? Simplemente agregaría un comentario si estuviera preocupado por la legibilidad. Ver: var newArray = oldArray.slice (); // Clone oldArray to newArray
dudewad
12
@ GáborImre Lo entiendo, claro. Pero responder un problema de ingeniería específico al incluir una biblioteca completa en mi opinión no es útil, es un diseño hinchado. Veo que los desarrolladores hacen mucho eso, y luego terminas con un proyecto que incluía un marco completo para reemplazar tener que escribir una sola función. Sin embargo, solo mi MO.
dudewad
55
Lección aprendida: no confunda .slice()con .splice(), lo que le da una matriz vacía. Gran diferencia.
crazypeter
531

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.

// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';

// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};

// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); // or `new function () {}`

A partir de estos elementos podemos crear tres tipos de matrices.

// 1) Array of literal-values (boolean, number, string) 
const type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
const type2 = [[], {}];

// 3) Array of prototype-objects (function)
const type3 = [function () {}, function () {}];

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.

Técnicas de copia profunda de Javascript por tipos de elementos

  • Matriz de valores literales (tipo1)
    El [...myArray], myArray.splice(0), myArray.slice(), y myArray.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 la JSON.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.

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

Entonces para responder la pregunta ...

Pregunta

var arr1 = ['a','b','c'];
var arr2 = arr1;

Me di cuenta de que arr2 se 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?

Responder

Debido a que arr1es 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.

// Highest performance for deep copying literal values
arr2 = [...arr1];

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.slice();
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above
tfmontague
fuente
1
Muchos de estos enfoques no funcionan bien. Usar el operador de asignación significa que debe reasignar el valor literal original de arr1. Es muy raro que ese sea el caso. Usando spliceborra arr1, así que eso no es una copia en absoluto. El uso JSONfallará si alguno de los valores de la matriz son Funciones o tienen prototipos (como a Date).
Dancrumb
Usar el empalme es una solución parcial. Fallará en muchos más casos que JSON. Splice crea una copia profunda de cadenas y números, cuando mueve valores, nunca dijo que devuelve una copia.
tfmontague
1
¿Por qué empalmar (0)? ¿No debería ser slice ()? Creo que se supone que no modifica la matriz original, lo que hace el empalme. @JamesMontagne
helpse
2
el empalme creará punteros a los elementos en la matriz original (copia superficial). splice (0) asignará nueva memoria (copia profunda) para elementos en la matriz que son números o cadenas, y creará punteros para todos los demás tipos de elementos (copia superficial). Al pasar un valor inicial de cero al método de función de empalme, no empalmará ningún elemento de la matriz original y, por lo tanto, no lo modificará.
tfmontague
1
En realidad, solo hay un tipo de matriz: una matriz de "algo". No hay diferencia entre [0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]y cualquier otra matriz.
wizzwizz4
189

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:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

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

Luke Femur
fuente
1
Esto no funcionará para una copia profunda. Deep Clone an Array en JavaScript .
SNag
151

No se necesita jQuery ... Ejemplo de trabajo

var arr2 = arr1.slice()

Esto copia la matriz desde la posición inicial 0hasta 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 mismas Object. Entonces, en este caso, parecería que la matriz se copia por referencia aunque la matriz se copie realmente.

jondavidjohn
fuente
12
No, esto no sería una copia profunda.
jondavidjohn
Prueba esto; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
pradeep1991singh
2
¿Cuál es la diferencia entre esta respuesta y la respuesta aceptada?
Isaac Pak
obteniendo un error en la consola para su ejemplo dado "TypeError: window.addEvent no es una función"
Ravi Sharma
72

Una alternativa a slicees concat, 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:

var array2 = [].concat(array1);

El segundo método es:

var array2 = array1.concat();

Cohen (en los comentarios) señaló que este último método tiene un mejor rendimiento .

La forma en que esto funciona es que el concatmé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 array1es undefined, puede devolver una matriz vacía de la siguiente manera:

var array2 = [].concat(array1 || []);

O, para el segundo método:

var array2 = (array1 || []).concat();

Tenga en cuenta que también se puede hacer esto con slice: var array2 = (array1 || []).slice();.

Ninjakannon
fuente
31
En realidad también puedes hacer: var array2 = array1.concat (); Es mucho más rápido con respecto al rendimiento. (JSPerf: jsperf.com/copy-simple-array y jsperf.com/copy-array-slice-vs-concat/5
Cohen
55
Vale la pena señalar que si array1 no es una matriz, [].concat(array1)devuelve, [array1]por ejemplo, si está indefinido, obtendrá [undefined]. A veces lo hagovar array2 = [].concat(array1 || []);
lee penkman
60

Así es como lo hice después de probar muchos enfoques:

var newArray = JSON.parse(JSON.stringify(orgArray));

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 ...)

Chtiwi Malek
fuente
44
Ésta es la mejor. Utilicé el mismo método hace mucho tiempo y creo que no hay más sentido en los bucles recursivos de la vieja escuela
Vladimir Kharlampidi
1
Tenga en cuenta que esta opción no maneja bien las estructuras tipo gráfico: se bloquea en presencia de ciclos y no conserva las referencias compartidas.
Ruben
1
Esto también falla para cosas como Date, o de hecho, cualquier cosa que tenga un prototipo. Además, undefineds se convierte en nulls.
Dancrumb
77
¿Nadie es lo suficientemente valiente como para comentar sobre la gran ineficiencia tanto en la CPU como en la memoria de serializar el texto y luego volver a analizarlo en un objeto?
Lawrence Dol
3
Esta solución es la única que funcionó. Usar slice () es realmente una solución falsa.
20

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:

Object.prototype.clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (i in this) {
        if (i == 'clone') 
            continue;
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        } 
        else 
            newObj[i] = this[i]
    } return newObj;
};

Y simplemente usa

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

Funcionará.

sarvesh singh
fuente
2
me sale este error cuando agrego este código a mi página '
Error de rango no capturado
1
Mis disculpas, este error ocurre en Chrome si no se declara arr1. así que copié y pegué el código anterior, y recibo el error, sin embargo, si declaro el arreglo arr1, entonces no obtengo el error. Podría mejorar la respuesta declarando arr1 justo por encima de arr2, veo que hay bastantes 'nosotros' que no reconocimos que teníamos que declarar arr1 (en parte porque cuando estaba evaluando su respuesta, estaba apurado y necesitaba algo que 'simplemente funciona')
sab
.slice()todavía funciona bien incluso si tiene objetos en su matriz: jsfiddle.net/edelman/k525g
Jason
77
@Jason, pero los objetos todavía apuntan al mismo objeto, por lo que cambiar uno cambiará al otro. jsfiddle.net/k525g/1
Samuel
Excelente código Una pregunta que tengo es que intenté copiar una matriz en otra como esta var arr1 = new Array () y luego var arr2 = arr1; Si cambio algo en arr2, el cambio también ocurre en arr1. Sin embargo, si uso el prototipo de clon que hiciste, en realidad crea una nueva instancia completa de esa matriz o, en otras palabras, la copia. Entonces, ¿es esto un problema del navegador? o javascript establece por defecto las dos variables apuntando una a otra con el uso de punteros cuando alguien hace var arr2 = arr1 y ¿por qué no sucede con las variables enteras? ver jsfiddle.net/themhz/HbhtA
themhz
17

Desde ES2015,

var arr2 = [...arr1];
Boopathi Rajaa
fuente
17

Personalmente, creo que Array.from es una solución más legible. Por cierto, solo ten cuidado con el soporte de su navegador.

//clone
let x = [1,2,3];
let y = Array.from(x);

//deep clone
let clone = arr => Array.from(arr,item => Array.isArray(item) ? clone(item) : item);
let x = [1,[],[[]]];
let y = clone(x);
Luis
fuente
1
Sí, esto es muy legible. La .slice()solución es completamente intuitiva. Gracias por esto.
Banago
15

¡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ón

y

let clonedArray = _.cloneDeep(array) documentación

ulou
fuente
11

Si se encuentra en un entorno de ECMAScript 6 , utilizando el Operador Spread puede hacerlo de esta manera:

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>

Walter Chapilliquen - wZVanG
fuente
9

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

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

Lo mismo ocurre con la matriz de objetos, se copiarán por referencia, debe copiarlos manualmente

A.Zaben
fuente
¡Esta respuesta merece un lugar cerca de la parte superior de la página! Estaba trabajando con sub matrices multidimensionales y no podía entender por qué las matrices internas siempre se copiaban por ref y no por val. Esta lógica simple resolvió mi problema. ¡Te daría +100 si es posible!
Mac
8

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?

let arr = [1,2,3,4,5];

Copiar una matriz en ES6

let arrCopy = [...arr]; 

Copiar n matriz en ES5

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

¿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:

arrCopy[1] = 'adding new value this way will unreference';

Cuando asigna un nuevo valor a la variable, está cambiando la referencia misma y no afecta el objeto / matriz original.

Lee mas

DevWL
fuente
6

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:

var arr = [1, 2, 3, 4, 5];

1) Recorrer la matriz en una función y devolver una nueva matriz, como esta:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

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:

var arr2 = arr.slice(); // make a copy of the original array

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:

var arr2 = arr.concat();

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:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Método Array.from, esto no es ampliamente compatible, antes del uso verifique el soporte en diferentes navegadores:

const arr2 = Array.from(arr);

6) Modo ECMA6, tampoco totalmente compatible, pero babelJs puede ayudarlo si desea transpilar:

const arr2 = [...arr];
Alireza
fuente
6
let a = [1,2,3];

Ahora puede hacer cualquiera de los siguientes para hacer una copia de una matriz.

let b = Array.from(a); 

O

let b = [...a];

O

let b = new Array(...a); 

O

let b = a.slice(); 

O

let b = a.map(e => e);

Ahora, si cambio un,

a.push(5); 

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.

Nitesh Ranjan
fuente
1
¿Cuál es el más rápido?
Marc Frame
5

Yo personalmente preferiría esta manera:

JSON.parse(JSON.stringify( originalObject ));
Diemauerdk
fuente
Entonces, ¿cómo se sugiere aquí ?
Script47
4

En mi caso particular, necesitaba asegurarme de que la matriz permaneciera intacta, así que esto funcionó para mí:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}
Brent Keller
fuente
2
+1 por no agregar oscuridad a su código llamando a una función que hace exactamente lo mismo, pero de una manera menos obvia. El corte puede ser más eficiente bajo el capó, pero para cualquiera que trabaje en el código, esto muestra su intención. Además, facilita la optimización posterior, si desea (por ejemplo) filtrar lo que está copiando. Sin embargo, tenga en cuenta que esto no maneja la copia profunda, y los mismos objetos internos se pasan a la nueva matriz, por referencia. Esto podría ser lo que quieres hacer, puede que no.
sincronizar
4

Haga una copia de la matriz / objeto multidimensional:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

Gracias a James Padolsey por esta función.

Fuente: aquí

tinta
fuente
3

Dan, no necesitas usar trucos elegantes. Todo lo que necesita hacer es hacer una copia de arr1 haciendo esto.

var arr2 = new Array(arr1);

Ahora arr1y arr2hay dos variables de matriz diferentes almacenadas en pilas separadas. Mira esto en jsfiddle .

DragoRaptor
fuente
Esto no copia la matriz. Crea una matriz con un elemento que hace referencia al original (es decir var arr2 = [arr1];).
Timothy003
3

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:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

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:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

¡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:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

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.parseen conjunto con JSON.stringify, de esta manera:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

Rendimiento de la copia:

Entonces, ¿cuál elegimos para un rendimiento óptimo? Resulta que el método más detallado, el forbucle tiene el mayor rendimiento. Use el forbucle 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 usar JSON.parse(JSON.stringify(arr))(mucha sobrecarga) si no se requiere un clon profundo y el rendimiento es un problema.

Prueba de rendimiento de origen

Willem van der Veen
fuente
3

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).

new_array = old_array.slice()

o

new_array = old_array.map((elem) => elem)

o

const new_array = new Array(...old_array);

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.

var new_array = JSON.parse(JSON.stringify(old_array));

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 .

abhinav1602
fuente
Muchas gracias, su respuesta fue el único que trabajó para mi escenario,
Albert sh
2

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:

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

Puede buscar más información en Google sobre valores primitivos inmutables y referencias de objetos mutables.

Sotiris
fuente
1
No tiene que copiar explícitamente las propiedades de los objetos de la matriz. Ver la respuesta de Chtiwi Malek.
Magne
2

El uso de jQuery deep copy se puede hacer de la siguiente manera:

var arr2 = $.extend(true, [], arr1);
Oleksandr Tsurika
fuente
2

También puede usar el operador de propagación ES6 para copiar la matriz

var arr=[2,3,4,5];
var copyArr=[...arr];
ankur kushwaha
fuente
2

Aquí hay algunas formas más de copiar:

const array = [1,2,3,4];

const arrayCopy1 = Object.values(array);
const arrayCopy2 = Object.assign([], array);
const arrayCopy3 = array.map(i => i);
const arrayCopy4 = Array.of(...array );

Ganesh Phirke
fuente
2

Ejemplos rápidos:

  1. Si los elementos de la matriz son tipos primitivos (cadena, número, etc.)

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]

  1. Si los elementos de la matriz son literales de objeto, otra matriz ({}, [])

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

  1. Solución para 2 : Copia profunda por elemento por elemento

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
arr2 = JSON.parse(JSON.stringify(arr1));
arr2.pop();	  // OK - don't affect arr1
arr2[0].x = 'z';  // OK - don't affect arr1
arr2[1][0] = 9;	  // OK - don't affect arr1

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

SridharKritha
fuente
1

Aquí hay una variante:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */
Zyox
fuente
No es una mala idea, aunque es mejor que use JSON stringify / parse en lugar de eval, y otra comparación de jsPerf sería bueno para verificar, también tenga en toSourcecuenta que no es estándar y no funcionará en Chrome, por ejemplo.
dmi3y
1

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:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

Referencia: aquí

O Array.prototype.mappuede usarse con una función de identidad:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

Referencia: aquí

Ashraf Sabry
fuente
+1 por mencionar Array.from, que ahora es compatible con todos los principales navegadores, excepto Internet Explorer ( fuente ). .
mgthomas99
Tenga en cuenta Array.fromque mutará los datos, no proporciona copia profunda / clonación profunda.
Sudhansu Choudhary
1

Para la matriz ES6 que contiene objetos

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}
askilondz
fuente