Loredra L
Loredra L

Reputation: 1553

Ways to keep an Array unchanged when pasting them as argument to function Javascript

I have an Array of objects A

And I have 2 different drawing functions which change A completely in their own ways. I would like to keep A unchanged. Is there best practices how to do it? My current solution is somehow feels unnatural:

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
}

Upvotes: 1

Views: 371

Answers (4)

EvSunWoodard
EvSunWoodard

Reputation: 1280

What I would do is use the Array.from() method, to pass a new array into your function. So, when you call drawGraphX(A), instead call drawGraphX(Array.from(A)). This will create a new Array of the same data you had in 'A'. Easy Peasy.

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

or

drawGraphX(Array.from(A));

Edit: As netRat and Jonasw pointed out. This will make a new array, but it keeps references to the individual objects. Meaning that while mutating the Array will not change the source array, changing any of the objects shared by the two arrays will change the source material. I.E.:

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

while

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

Proof of concept: https://jsfiddle.net/5hLjajc0/1/

Upvotes: 1

pilczuk
pilczuk

Reputation: 196

Try putting drawGraphX(A.slice()) slice returns copy of array if shallow copy is fine for you and it is just about array itself, however remember that you are in fact not cloning objects so

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

will return you "foobar"

so it is fine if you mutate array itself but not elements (note that the same comment goes to Array.from(A) solution.

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138267

The more elegant solution would be sth like a switch, that if an objs is undefined, take a parents one:

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 like this:

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

Its mainly an improved version of prototypes:

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

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

This will allow you to access the prototypes props, wich cant be overriden that easily:

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

This doesnt override the prototype, it extends the arg... To override you can still do

arg.prototype[0]=function(){
 alert("hi prototype");
};

Upvotes: -1

Jamiec
Jamiec

Reputation: 136104

I suspect the real answer here is that you shouldn't be changing the data inside your function at all!

Lets imagine that A is an array of x/y points to be used for a chart

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

And your function just wants the x - are you doing this:

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

   // now draw the graph
}

In the above example, yes,, you will be changing the source of A as you've just passed a reference in to the function and updated the elements of that referenced array. This is bad practice, what you should be doing is this:

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

   // data is an array of just the x values
}

Upvotes: 2

Related Questions