Tengo una matriz de objetos A

Y tengo 2 funciones de dibujo diferentes que cambian A completamente a su manera. Me gustaría mantener A sin cambios. ¿Hay mejores prácticas para hacerlo? Mi solución actual es de alguna manera no natural:

var A;//Should stay the same always

drawGraphX(A){
//Modifying A here to draw but I would like the original A to stay the same
B=JSON.parse(JSON.stringify(A));
//So I do it with B
}

drawGraphY(A){
//Modifying A here to draw
B=JSON.parse(JSON.stringify(A));
//So I do it with B
}
1
Loredra L 10 ene. 2017 a las 19:00

4 respuestas

La mejor respuesta

¡Sospecho que la respuesta real aquí es que no debería cambiar los datos dentro de su función en absoluto !

Imaginemos que A es una matriz de puntos x / y que se utilizará para un gráfico

var A = [{x:1,y:1},{x:2,y:2},{x:3,y:3}];

Y su función solo quiere x: ¿está haciendo esto?

function drawGraphX(A){
   for(var i=0;i<A.length;i++)
      A[i] = A[i].x; 

   // now draw the graph
}

En el ejemplo anterior, sí, cambiará la fuente de A ya que acaba de pasar una referencia a la función y actualizó los elementos de esa matriz referenciada. Esta es una mala práctica, lo que debes hacer es esto:

function drawGraphX(A){
   var data = A.map(function(e){
       return e.x;
   });

   // data is an array of just the x values
}
2
Jamiec 10 ene. 2017 a las 16:27

Lo que haría es utilizar el método Array.from() para pasar una nueva matriz a su función. Entonces, cuando llame a drawGraphX(A), llame a drawGraphX(Array.from(A)). Esto creará una nueva matriz de los mismos datos que tenía en 'A'. Pan comido.

var b = Array.from(A);
drawGraphX(b);

O

drawGraphX(Array.from(A));

Editar: Como señalaron netRat y Jonasw. Esto creará una nueva matriz, pero conserva referencias a los objetos individuales. Lo que significa que si bien mutar la matriz no cambiará la matriz fuente, cambiar cualquiera de los objetos compartidos por las dos matrices cambiará el material fuente. ES DECIR.:

var a = [1,2];
var b = Array.from(a);
b[0] = b[0]++;
console.log(a); // will result [2,2];

Mientras

b.push[3];
console.log(a); // will result [1,2]
console.log(b); // will result [1,2,3];

Prueba de concepto: https://jsfiddle.net/5hLjajc0/1/

1
EvSunWoodard 11 ene. 2017 a las 15:43

Intente poner drawGraphX(A.slice()) sector devuelve copia de matriz si la copia superficial está bien para usted y se trata solo de la matriz en sí misma, sin embargo recuerde que de hecho no está clonando objetos

var A = [{test:'foo', test2:'bar'}, {test:'foo1', test2:'bar1'}];
var B = A.slice();
A[0].test = 'foobar';
console.log(B[0].test);

Te devolverá "foobar"

Así que está bien si mutas la matriz en sí pero no los elementos (ten en cuenta que el mismo comentario va a la solución Array.from(A).

1
pilczuk 10 ene. 2017 a las 17:06

La solución más elegante sería algo así como un interruptor, que si un objs no está definido, tome uno de los padres:

function switch(obj,prot){
 return function(keys,val){
  keys= keys.split(".");
  var el=obj;
  var par;
  for(key of keys){
    par=el
    el=el[key];        
  }
  if(el==undefined){
          var el=prot;
          var par;
          for(key of keys){
           par=el
           el=el[key];        
           }
   }
  if(value){
    par[keys[keys.length]]=value;
  }
  return el;
  };}

Use así:

prot=[0,1,3];//unchangeable
obj=[,5,];
callfunc(switch(obj,prot));
function callfunc(el){
//read
el("0");//0
el("1");//5
el("2");//3
//write
el("0", 12);//do not override prot
//also with multidim stuff:
el("0.a");
}

Es principalmente una versión mejorada de prototipos:

var obj={
 0:function(){
  alert("original prototype");
 },
 1:5
 }

 callfunc(Object.create(obj));//...
 callfunc(Object.create(obj));//...

Esto le permitirá acceder a los accesorios de los prototipos, que no se pueden anular tan fácilmente:

function callfunc(arg){
  arg[0]();//works as expected
  arg[0]=function(){
    alert("hi");
  }
  arg[0]();//hi
  }

Esto no anula el prototipo, extiende el argumento ... Para anular aún puede hacer

arg.prototype[0]=function(){
 alert("hi prototype");
};
-1
Jonas Wilms 10 ene. 2017 a las 16:43