valores recorrer obtener objetos modificar eliminar elementos elemento copiar buscar array agregar javascript arrays

javascript - recorrer - Copiar matriz por valor



obtener valores de un array javascript (28)

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 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?


Añadiendo a la solución de array.slice (); tenga en cuenta que si tiene matrices de matrices multidimensionales se copiarán por referencias. Lo que puedes hacer es hacer un bucle y dividir () 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 se aplica a la matriz de objetos, se copiarán por referencia, debe copiarlos manualmente.


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 una referencia, no 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 usar

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

Funcionará.


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


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 */


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

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

Esto creará una nueva copia en profundidad no relacionada con la primera (no una copia superficial).

Además, esto obviamente no clonará eventos y funciones, pero lo bueno es que lo puede hacer en una línea, y se puede usar para cualquier tipo de objeto (arreglos, cadenas, números, objetos ...)


Como sabemos en las matrices de Javascript y los objetos son por referencia, pero ¿de qué manera podemos copiar la matriz sin cambiar la matriz original más adelante?

Aquí hay algunas maneras 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 cortar una parte de la matriz, dividirá una parte de su matriz sin tocar el original, en la porción, si no especifica el inicio y el final de la matriz, dividirá la totalidad array y básicamente hacer una copia completa de la matriz, por lo que podemos decir fácilmente:

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

3) También método de contacto, esto es para combinar 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 es un método de clasificación y análisis, 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 soportado, antes de usarlo, verifique el soporte en diferentes navegadores:

const arr2 = Array.from(arr);

6) El modo ECMA6, tampoco es totalmente compatible, pero babelJs puede ayudarlo si desea realizar la transferencia:

const arr2 = [...arr];


Cuando queremos copiar una matriz utilizando 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 nuestra estructura de datos inicial (por ejemplo, Array) intacta. Hacemos esto haciendo una copia exacta de nuestra matriz para que esta se pueda transformar mientras que 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 los arrays 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 llevar 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 utilice estos métodos cuando haya objetos o matrices dentro de su matriz que desee copiar. Es decir, utilice estos métodos en matrices de primitivos solamente.

Si desea realizar una clonación profunda de una matriz javascript, use JSON.parse junto 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

Realización de la copia:

Entonces, ¿cuál elegimos para un rendimiento óptimo. Resulta que el método más detallado, el bucle for tiene el rendimiento más alto. Utilice el bucle for para realizar copias realmente intensivas de CPU (grandes / muchas matrices).

Después de eso, el método .slice() también tiene un rendimiento decente y también es menos detallado y más fácil de implementar para el programador. Le sugiero usar .slice() para su copia diaria de arreglos que no requieren mucha CPU. También evite usar JSON.parse(JSON.stringify(arr)) (muchos gastos generales) si no se requiere una clonación profunda y el rendimiento es un problema.

Prueba de rendimiento de la fuente


Dan, no hay necesidad de usar trucos de fantasía. Todo lo que necesitas hacer es hacer una copia de arr1 haciendo esto.

var arr2 = new Array(arr1);

Ahora arr1 y arr2 son dos variables de matriz diferentes almacenadas en pilas separadas. Mira esto en jsfiddle .


Desde ES2015,

var arr2 = [...arr1];


En Javascript, las técnicas de copia profunda dependen de los elementos de una matriz.
Vamos a empezar por ahi

Tres tipos de elementos

Los elementos pueden ser: valores literales, estructuras literales o prototipos.

// Literal values (type1) var booleanLiteral = true; var numberLiteral = 1; var stringLiteral = ''true''; // Literal structures (type2) var arrayLiteral = []; var objectLiteral = {}; // Prototypes (type3) var booleanPrototype = new Bool(true); var numberPrototype = new Number(1); var stringPrototype = new String(''true''); var arrayPrototype = new Array(); var 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) var type1 = [true, 1, "true"]; // 2) Array of literal-structures (array, object) var type2 = [[], {}]; // 3) Array of prototype-objects (function) var type3 = [function () {}, function () {}];

Las técnicas de copia profunda dependen de los tres tipos de matriz

Basándonos en los tipos de elementos de la matriz, podemos usar varias técnicas para realizar copias en profundidad.

  • Matriz de valores literales (tipo 1)
    Las myArray.splice(0) , myArray.slice() y myArray.concat() se pueden usar para realizar copias en profundidad de arrays con valores literales (booleano, número y cadena) solo; donde Slice tiene un rendimiento mayor que Concat ( http://jsperf.com/duplicate-array-slice-vs-concat/3 ).

  • Matriz de valores literales (tipo 1) y estructuras literales (tipo 2)
    La JSON.parse(JSON.stringify(myArray)) se puede utilizar para realizar una copia profunda de los valores literales (booleano, número, cadena) y las estructuras literales (matriz, objeto), pero no los objetos prototipo.

  • Todas las matrices (tipo 1, tipo 2, tipo 3)
    La técnica jQuery $.extend(myArray) se puede utilizar para realizar una copia profunda de 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 menor. Más sorprendentemente, $.extend() tiene un rendimiento más alto que la JSON.parse(JSON.stringify(myArray)) 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 mayor que $ .extend, y copia en profundidad todas las matrices.

    function copy(o) { var output, v, key; output = Array.isArray(o) ? [] : {}; for (key in o) { v = o[key]; output[key] = (typeof v === "object" && v !== null) ? copy(v) : v; } return output; }

Así que para responder a 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 arr1 es una matriz de valores literales (booleano, número o cadena), puede usar cualquier técnica de copia profunda descrita anteriormente, donde la slice tiene el mayor rendimiento.

// Highest performance for deep copying literal values arr2 = arr1.slice(); // Any of these techniques will deep copy literal values as well, // but with lower performance. 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


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]); }


Hacer copia de 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: Here


No se necesita jQuery ... Ejemplo de trabajo

var arr2 = arr1.slice()

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 espera 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 de las matrices contendrán referencias a los mismos Object . Entonces, en este caso, parecería que la matriz se copia por referencia, aunque la matriz se haya copiado realmente.


Para la matriz ES6 que contiene objetos

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


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


Podrías usar ES6 con Opeartor extendido, es más simple.

arr2 = [...arr1];

Hay limitaciones ... verifique la sintaxis de la documentación @ mozilla


Puedes hacerlo de la siguiente manera:
arr2 = arr1.map(x => Object.assign({}, x));



Se encuentra el Array.from recién introducido, pero desafortunadamente, en el momento de escribir este artículo, solo se admite en las versiones recientes de Firefox (32 y superior). Se puede utilizar simplemente de la siguiente manera:

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

Referencia: Here

O Array.prototype.map se puede usar con una función de identidad:

function identity(param) { return param; } var arr1 = [1, 2, 3], clone = arr1.map(identity);

Referencia: Here


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 primarios inmutables y referencias de objetos mutables.



Si su matriz contiene elementos del tipo de datos primitivos , como int, char, o cadena, etc. , puede utilizar uno de esos métodos que devuelve una copia de la matriz original como .slice () o .map () o el operador de difusió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) o más objetos anidados , entonces tendrá que asegurarse de que está haciendo una copia de todos los elementos desde el nivel superior hasta el último nivel; los objetos se utilizarán y eso significa que cambiar los valores en object_elements en new_array seguirá afectando a old_array. Puede llamar a este método de copia en cada nivel para realizar una COPIA PROFUNDA del 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 información 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));

Hay muchos otros métodos que puedes usar dependiendo de tus necesidades. He mencionado solo algunas de ellas para dar una idea general de lo que sucede cuando intentamos copiar una matriz en la otra por valor .


También puede utilizar el operador de propagación de ES6 para copiar Array

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


Una alternativa a la slice() es concat , que se puede utilizar de 2 maneras. El primero de estos 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 desempeño .

La forma en que funciona es que el método concat crea una nueva matriz que consta de los elementos en el objeto en el que se llama, seguida de los elementos de cualquier matriz que se le pasan como argumentos. Así que cuando no se pasan argumentos, simplemente copia la matriz.

Lee Penkman, también en los comentarios, señala que si existe la posibilidad de que array1 undefined esté undefined , puede devolver un array vacío de la siguiente manera:

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

O, para el segundo método:

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

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


Usando jQuery deep copy se podría hacer de la siguiente manera:

var arr2 = $.extend(true, [], arr1);


Utilizar esta:

var newArray = oldArray.slice();

Básicamente, la operación slice() 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 las referencias de objetos en la nueva matriz. Tanto la matriz original como la nueva se refieren al mismo objeto. Si un objeto referenciado cambia, los cambios son visibles tanto para las matrices nuevas como para las originales.

Los primitivos como cadenas y números son inmutables, por lo que los cambios en la cadena o el número son imposibles.


¡Importante!

La mayoría de las respuestas aquí funcionan para casos particulares .

Si no te importa el uso de objetos y accesorios profundos / anidados ( 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 de lodash:

let clonedArray = _.clone(array) documentation

y

let clonedArray = _.cloneDeep(array) documentation let clonedArray = _.cloneDeep(array)


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 objetos, 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 ] ]