Pregunta Copiar matriz por valor en JavaScript


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


1335
2017-09-20 13:38


origen


Respuestas:


Utilizar esta:

var newArray = oldArray.slice();

Básicamente, el rebanada() operación clona la matriz y devuelve la referencia a la nueva matriz. También tenga en cuenta que:

Para las referencias, cadenas y números (y no el objeto real), recorte las referencias de los 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.

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


2152
2017-09-20 13:41



En Javascript, las técnicas de copia profunda dependen de los elementos de una matriz.
Comencemos allí.

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

En función de los tipos de elementos de la matriz, podemos usar varias técnicas para copiar en profundidad.

Javascript deep copy techniques by element types

  • Matriz de valores literales (tipo1)
    los myArray.splice(0), myArray.slice()y myArray.concat() las técnicas se pueden usar para copiar profundamente matrices con valores literales (booleanos, números y cadenas) solamente; donde Slice tiene un mayor rendimiento que Concat (http://jsperf.com/duplicate-array-slice-vs-concat/3)

  • Matriz de valores-literal (tipo1) y estructuras-literales (tipo2)
    los JSON.parse(JSON.stringify(myArray)) La técnica se puede utilizar para copiar profundamente los valores literales (booleanos, números, cadenas) y las estructuras literales (matriz, objeto), pero no los objetos prototipo.

  • Todas las matrices (tipo1, tipo2, tipo3)
    El jQuery $.extend(myArray) La técnica se puede usar para copiar en profundidad todos los tipos de matriz. Bibliotecas como Guion bajo y Lo-dash ofrecen funciones similares de copia profunda para jQuery  $.extend(), sin embargo, tienen un menor rendimiento. Más sorprendentemente $.extend() tiene un mayor rendimiento que el 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 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;
    }  
    

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 

Porque arr1 es una matriz de valores literales (booleanos, numéricos o de cadena), puede usar cualquier técnica de copia profunda discutida anteriormente, donde slice tiene el más alto 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

363
2018-05-08 08:36



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á según lo esperado 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, diga de tipo Object. La matriz será ser copiado, pero ambas matrices contendrán referencias a la misma Objectes Entonces, en este caso, parece que la matriz se copia por referencia aunque la matriz en realidad está copiado


146
2017-09-20 13:39



Puede usar spreads de array ... para copiar matrices.

const itemsCopy = [...items];

Además, si desea crear una nueva matriz con la existente formando parte de ella:

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

Los diferenciales de matriz están ahora compatible con todos los principales navegadores pero si necesita soporte más antiguo, use mecanografiado o babel y compile a ES5.

Más información sobre diferenciales


136
2017-07-03 14:46



Una alternativa a slice es concat, que se puede usar 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 rendimiento.

La forma en que esto funciona es que concat método crea una nueva matriz que consiste en los elementos en el objeto sobre el que se llama, seguido de los elementos de las matrices que se le pasan como argumentos. 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 es 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 puede hacer esto con slice: var array2 = (array1 || []).slice();.


67
2017-10-18 00:11



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 es una copia poco profunda).

También obviamente esto no clonará eventos y funciones, pero lo bueno es que puedes hacerlo en una línea, y puede ser usado para cualquier tipo de objeto (matrices, cadenas, números, objetos ...)


39
2018-04-23 13:32



Algunos de los métodos mencionados funcionan bien cuando se trabaja con tipos de datos simples como el número o la 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á.


17
2017-12-12 16:22



Desde ES2015,

var arr2 = [...arr1];

14
2017-12-24 07:14