2009-02-19 6 views
178

Duplicar posibles:
What is the most efficient way to clone a JavaScript object?(Deep) copiar una matriz usando jQuery

necesito copiar un array (ordenada, no asociativa) de los objetos. Estoy usando jQuery. Inicialmente intentado

jquery.extend({}, myArray) 

pero, naturalmente, esto me devuelve un objeto, donde necesito una matriz (realmente aman jQuery.extend, por cierto).

Entonces, ¿cuál es la mejor manera de copiar una matriz?

+0

Si no quiere un objeto a cambio, especifique '[]' en lugar de '{}' – Ashwin

Respuesta

261

Desde Array.slice() no hace una copia completa, que no es adecuado para las matrices multidimensionales:

var a =[[1], [2], [3]]; 
var b = a.slice(); 

b.shift().shift(); 
// a is now [[], [2], [3]] 

en cuenta que aunque he utilizado shift().shift() anteriormente, el punto es simplemente que b[0][0] contiene una puntero a a[0][0] en lugar de un valor.

Asimismo delete(b[0][0]) también causa a[0][0] a borrar y b[0][0]=99 también cambia el valor de a[0][0] a de 99.

extend método de jQuery qué realizar una copia profunda cuando un verdadero valor se pasa como argumento inicial:

var a =[[1], [2], [3]]; 
var b = $.extend(true, [], a); 

b.shift().shift(); 
// a is still [[1], [2], [3]] 
+13

Gracias Noah. Parece que mi mayor problema fue que estaba dando $ .extend y object como su primer argumento, no una matriz. – morgancodes

+2

¿Puede explicar cuál es el propósito de b.shift(). Shift() aquí? – Lijo

+1

b solo está siendo manipulado para mostrar que a y b no tienen el mismo valor. ¿No deberían a y b representarse como [[3]]? Shift elimina el primer valor de una matriz por completo, ya sea de cualquier tipo. No realiza una búsqueda recursiva para un tipo primitivo y luego elimina eso. La longitud de una matriz que contiene el contexto para el método siempre disminuye en 1 y se edita en su lugar. – danronmoon

26

$.extend(true, [], [['a', ['c']], 'b'])

Eso debería hacerlo por usted.

+0

Esto no funcionará para matrices multidimensionales, tiene que usar "verdadero" como primer argumento como se menciona en la respuesta de @Noah Sussman –

16

que se dan cuenta de que usted está buscando una copia "profunda" de una matriz, pero si sólo tiene una única matriz de nivel se puede utilizar esto:

Copia de una matriz de JS nativa es fácil. Use el método Array.slice() que crea una copia de parte/todo el conjunto.

var foo = ['a','b','c','d','e']; 
var bar = foo.slice(); 

ahora foo y bar son 5 arrays miembros de 'a', 'b', 'c', 'd', 'e'

de bar curso es una copia, no una referencia. .. así que si usted hizo esto al lado ...

bar.push('f'); 
alert('foo:' + foo.join(', ')); 
alert('bar:' + bar.join(', ')); 

se pondría manos:

foo:a, b, c, d, e 
bar:a, b, c, d, e, f 
+24

Tenga en cuenta que esto no es una copia profunda. –

+0

similar: var a = [1,2,3]; var b = ([]). Concat (a); b es una copia –

+4

Array.slice no proporciona una copia profunda, que es específicamente la pregunta que se hace aquí. – Ryley

12

Todo en JavaScript es pase por referencia, así que si quieres una copia verdadera profundidad de los objetos de la matriz, el mejor método que se me ocurre es serializar toda la matriz a JSON y después de -serializarlo de nuevo.

+1

Las primitivas no se pasan por referencia. Objetos (incluyendo arreglos) son, sin embargo. –

2

planeo en la liberación de este código en la próxima versión de jPaq, pero hasta entonces, puede usar esta opción si su objetivo es hacer una copia profunda de matrices:

Array.prototype.clone = function(doDeepCopy) { 
    if(doDeepCopy) { 
     var encountered = [{ 
      a : this, 
      b : [] 
     }]; 

     var item, 
      levels = [{a:this, b:encountered[0].b, i:0}], 
      level = 0, 
      i = 0, 
      len = this.length; 

     while(i < len) { 
      item = levels[level].a[i]; 
      if(Object.prototype.toString.call(item) === "[object Array]") { 
       for(var j = encountered.length - 1; j >= 0; j--) { 
        if(encountered[j].a === item) { 
         levels[level].b.push(encountered[j].b); 
         break; 
        } 
       } 
       if(j < 0) { 
        encountered.push(j = { 
         a : item, 
         b : [] 
        }); 
        levels[level].b.push(j.b); 
        levels[level].i = i + 1; 
        levels[++level] = {a:item, b:j.b, i:0}; 
        i = -1; 
        len = item.length; 
       } 
      } 
      else { 
       levels[level].b.push(item); 
      } 

      if(++i == len && level > 0) { 
       levels.pop(); 
       i = levels[--level].i; 
       len = levels[level].a.length; 
      } 
     } 

     return encountered[0].b; 
    } 
    else { 
     return this.slice(0); 
    } 
}; 

El siguiente es un ejemplo de cómo llamar a esta función para hacer una copia profunda de un conjunto recursivo:

// Create a recursive array to prove that the cloning function can handle it. 
var arrOriginal = [1,2,3]; 
arrOriginal.push(arrOriginal); 

// Make a shallow copy of the recursive array. 
var arrShallowCopy = arrOriginal.clone(); 

// Prove that the shallow copy isn't the same as a deep copy by showing that 
// arrShallowCopy contains arrOriginal. 
alert("It is " + (arrShallowCopy[3] === arrOriginal) 
    + " that arrShallowCopy contains arrOriginal."); 

// Make a deep copy of the recursive array. 
var arrDeepCopy = arrOriginal.clone(true); 

// Prove that the deep copy really works by showing that the original array is 
// not the fourth item in arrDeepCopy but that this new array is. 
alert("It is " 
    + (arrDeepCopy[3] !== arrOriginal && arrDeepCopy === arrDeepCopy[3]) 
    + " that arrDeepCopy contains itself and not arrOriginal."); 

Puedes jugar con este código here at JS Bin.

+1

Interesante. @ Chris West ¿Puede decirnos qué problemas tienen los destinatarios de su respuesta que jQuery no ofrece? Muchas gracias. – iainH

5

Si desea utilizar JavaScript puro continuación, intente esto:

var arr=["apple","ball","cat","dog"]; 
var narr=[]; 

for(var i=0;i<arr.length;i++){ 
    narr.push(arr[i]); 
} 
alert(narr); //output: apple,ball,vat,dog 
narr.push("elephant"); 
alert(arr); // output: apple,ball,vat,dog 
alert(narr); // apple,ball,vat,dog,elephant 
1

¿qué hay de los tipos complejos? cuando matriz contiene objetos ... o cualquier otra cosa

Mi variante:

Object.prototype.copy = function(){ 
    var v_newObj = {}; 
    for(v_i in this) 
     v_newObj[v_i] = (typeof this[v_i]).contains(/^(array|object)$/) ? this[v_i].copy() : this[v_i]; 
    return v_newObj; 
} 

Array.prototype.copy = function(){ 
    var v_newArr = []; 
    this.each(function(v_i){ 
     v_newArr.push((typeof v_i).contains(/^(array|object)$/) ? v_i.copy() : v_i); 
    }); 
    return v_newArr; 
} 

No es versión final, sólo una idea.

PD: método cada uno y contiene prototipos también.

Cuestiones relacionadas