I'm having a strange situation in JavaScript where I am creating an Object and then passing it as an Argument to a Function which then updates the values and then returns a new updated Object.
function objBuild() {
var obj_old = {}; // original object
var obj_new = {}; // updated object
// set values for original object
obj_old.val01 = "val01_old";
obj_old.val02 = "val02_old";
obj_old.val03 = "val03_old";
// set values for new object using
// the original object as a template
obj_new = objUpdate(obj_old);
console.log(obj_old); // this shows obj_new data which I don't want
console.log(obj_new); // this shows obj_new data which I want
}
function objUpdate(obj) {
obj.val03 = "val03_new";
return obj;
}
I was expecting the new Object to be updated with the new Value, which it is, however the old Object is updated as well.
Maybe the function is taking the old Object as a reference and even though I'm returning a separate value it remembers what's happened to it?
I'm not sure but if that is the case is it possible to keep the old Object intact?
Please read: Is JavaScript a pass-by-reference or pass-by-value language?
In javascript, objects are "technically" passed by "reference". Hence, the original value is altered, because obj is, in fact, the original object.
You need to clone the object, and there is a vast scenario about "how" you should do that, since object may be shallow copied or deep copied. Read more about that here: What is the most efficient way to deep clone an object in JavaScript?
and here: How do I correctly clone a JavaScript object?
Anyway, to fix your issue, just use Object.assign on a brand new object to copy the values of the original object, for your case, it's just enough, despite I recommend you to read the above posts to learn when and how to properly copy objects.
function objBuild() {
var obj_old = {}; // original object
var obj_new = {}; // updated object
// set values for original object
obj_old.val01 = "val01_old";
obj_old.val02 = "val02_old";
obj_old.val03 = "val03_old";
// set values for new object using
// the original object as a template
obj_new = objUpdate(obj_old);
console.log(obj_old); // this shows obj_new data which I don't want
console.log(obj_new); // this shows obj_new data which I want
}
function objUpdate(obj) {
var _cloned = Object.assign({}, obj);
_cloned.val03 = "val03_new";
return _cloned;
}
objBuild();
You're not actually creating a new object, you're setting the old object to the new object. So you're correct, the old object value is still being referenced.
If you want to make a new object, and you don't have any nested objects, I would use Object.assign(). This makes a shallow copy of the object. You could do something like this:
obj_new = objUpdate(Object.assign({}, obj_old));
This will create a new object with the enumerable properties of the old object.
If you have nested objects, these will still be copied by reference, so I would loop over the object and copy the properties that way.
Remember that objects, including arrays are passed by reference while strings, booleans and numbers are passed by value.
Here, you are passing object(by reference) so it is modifying the values of old object. Both old and new objects are pointing to the same value.
function objBuild() {
var obj_old = {}; // original object
var obj_new = {}; // updated object
// set values for original object
obj_old.val01 = "val01_old";
obj_old.val02 = "val02_old";
obj_old.val03 = "val03_old";
// set values for new object using
// the original object as a template
obj_new = objUpdate(obj_old);
console.log(obj_old); // this shows obj_new data which I don't want
console.log(obj_new); // this shows obj_new data which I want
}
function objUpdate(obj_old) {
var obj = JSON.parse(JSON.stringify(obj_old));
obj.val03 = "val03_new";
return obj;
}
objBuild();
Related
When I put an object into array using push method and then change the value of the object, the value of the object in the array also changes. How to prevent it?
function onLoad() {
let array = []
let object = {}
object[1] = [1,2]
array.push(object)
object[1] = [1,3]
console.log(array)
}
onLoad();
I would like the code console [{1,2}] but it will console [{1,3}].
Would anyone know how to fix this?
In JavaScript, Complex data types(Objects and arrays) are copied by reference whereas primitive data types(Strings, Numbers, and Boolean) are copied by value
Simply put , Pass by reference will not create a copy instead refer to the same memory.
So original objects and arrays will be changed
Copy by value will create a copy of the value and hence original value will not be changed
function change(array1){
array1[0] = "changed";
}
var original = ["original"]
change(original)
console.log(original)
function changePrimitive(input) {
input = "changed"
}
var original = "original"
changePrimitive(original)
console.log(original);
I have created a copy of a variable using Object.assign and I am able to change an array within the copy of the object fine without affecting the original object. However, if I try and update a value within an array on the copied object this is also affecting the original object (i.e. the changes are made to both "job" and "updatedJob").
I have the following code:
// Create copy of "job" object which has been passed through
let updatedJob = Object.assign({}, job);
// Remove images from updated job object
updatedJob.Images = null;
// Remove checklist images from updated job object
_.each(updatedJob.Checklists, function (checklist) { checklist.Image = null; });
As you can see I have created a copy of the "job" object that has been passed through.
If I then change the "Images" array of the "updateJob" object (to null) this works fine and does not affect the original "job" object (i.e. the original "job" object still has images intact).
However in the last line of the code I am trying to iterate the "Checklists" array witin the "updatedJob" object and change just the "Image" property to "null" for each one but doing this also updates the original "job" object.
How is this possible when the "updatedJob" object should be a copy of the original "job" object therefore any changes I make to it should not affect the original "job" object?
As stated in comments and other answers, you're doing a shallow copy. Does that _.each() in your code indicate that you're using lodash?
If so, use the deepClone() method so that items are copied recursively:
let updatedJob = _.cloneDeep(job)
Otherwise, there are other questions on SO that deal with this topic that will provide a suitable solution.
Object.assign does a shallow copy: It copies all the key-value pairs of one object into another, just like this:
const from = { primitive: "string", complex: { } }, to = {};
// Object.assign(from, to) basically does
to.primitive = from.primitive; // primitives are copied
to.complex = from.complex; // complex values references get copied, not the value itself
However, objects (arrays are objects too) are copied by reference, so in your case, both objects' Checklists properties point to the same array.
You could create a new array by using .map and reassign the property to point to the new array:
updatedJob.Checklists = updatedJob.Checklists.map(checklist => ({ ...checklist, Image: null }));
The reference thing here applies here again too, setting .Image to null would affect the object referenced in both arrays, therefore we have to copy these objects too.
This question already has answers here:
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 4 years ago.
So I have a property in a class called 'tiles' which contains information about a checkers board game's state. I'm trying to push this property to an array called 'moves' every time I make a legal move and at the start of the game. But the problem is, every time I push the new tiles property, the previous elements in the moves array change to the values of the latest pushed tiles.
I understand this is happening because the object is being passed by reference and hence replaces old elements in array because they now point to the same object, which is the latest value of the property tiles. So with my code given below, is there a way I can push this object not by reference but each different individual state of 'tiles' that resulted due to legal moves.
Here is my snippet: App.js
App = function () {
var self = this;
self.tiles = [];
// this is populated with objects from a json file
//code to fetch json and save it to self.tiles
//more code
this.startGame = function () {
//other code
self.moves.push(self.tiles);
};
this.makeMove = function () {
//other code
self.moves.push(self.tiles);
};
};
So what I expect is in self.moves array, the tiles should point to different objects instead of the same object. It should contain different states of self.tiles but right now, as I push the property, the elements of 'moves' array is overwritten by the latest self.tiles value.
Any help to solve this problem will be highly appreciated. Thanks!
You should use JSON.parse(JSON.stringify()) to clone a nested object.You can use Object.assign to clone shallow object
App = function () {
var self = this;
self.tiles = [];
// this is populated with objects from a json file
//code to fetch json and save it to self.tiles
//more code
this.startGame = function () {
//other code
self.moves.push(JSON.parse(JSON.stringify(self.tiles)));
};
this.makeMove = function () {
//other code
self.moves.push(JSON.parse(JSON.stringify(self.tiles)));
};
};
I've fiddled around with it for a bit and found you can use the spread operator like so:
var a = {b: 1, c: 2}
var array1 = []
array1.push({...a})
a.c=3
console.log(array1) // [0: {b: 1, c: 2}]
console.log(a) // {b: 1, c: 3}
MDN: Spread in object literals
The only way you can address your issue is to pass the clone of the object you want to push into the vector. In such cases normally you would write a clone() method to your object that returns a deep copy of itself. The object returned by this method can be pushed to the array.
I would like to understand well something i observe more and more.
In some circonstances, different instances from a same model change their attributes the same way (if i have 2 UserModel A and B, if i change A, B will be affected the same way).
I observed some practical cases:
When i send an instance of a model to a view constructor, they are linked, if i change the model in my view, the outside one will be affected the same way. I guess sometime we just send a pointer and not a copy of the instance to the view.
More specific with some code;
A = new UserModel();
B = new UserModel();
var Data = A.get('info'); //where info = {some: "thing"};
Data.some = 'other';
B.set('info', Data); //A.get('info') == B.get('info')
Because i got the object info and not only the attributes separately (i tested it and there is no repercution between the values this way).
So my question is, are we always using pointers with objects in javascript ? Is it specific to backbone ? I would like to understand what is behind this behavior.
Thanks.
Objects and Arrays are passed or assigned as references in javascript, not copies. If you want a copy of an object or an array, you have to explicity make a copy.
Simpler types such as numbers, boolean are copied when assigned or passed.
Strings are a bit of special case. They are passed as references, but since strings are immutable (can't be changed), you can't really use a string reference for anything because any attempt to modify the string creates a new string.
A couple examples:
// arrays assigned by reference
var a = [1,2,3];
var b = a;
a[0] = 0;
alert(b[0]); // alerts 0 because b and a are the same array
// objects assigned by reference
var c = {greeting: "hello"};
var d = c;
c.greeting = "bye";
alert(d.greeting); // alerts "bye" because c and d are the same object
// numbers assigned as copies
var e = 3.414;
var f = e;
e = 999;
alert(f); // alerts 3.414 because f is its own copy of the original number
// make a copy of an array
var g = [1,2,3];
var h = g.slice(0); // h is now a copy
h[0] = 9;
alert(g); // shows [1,2,3]
alert(h); // shows [9,2,3]
The same is true for passing arguments to a function or returning values from a function. Unless an explicit copy is created, arrays and objects are passed or returned by reference.
A shallow copy of an array can be made with the .slice() method.
var arr1 = [1,2,3];
var arr2 = arr1.slice(0); // make independent copy of first array
A shallow copy of an object can be made by copying each property from the original object to a new object.
Deep copies involve testing the type of each item being copied and recursing on the object if it is an object or array so nested objects and arrays are copied too.
Alright stackoverflow,
I've been working hours on solving an issue in javascript (writing in NodeJS server) but I really don't get it.
This is what happens:
var data = {x: 50};
var temp = data;
temp.x = 100;
console.log(data.x);
//logs 100
I have tested this exact code and it really shows 100.
My question:
How do I clone a var to a temp one and change the temp var without the original changing along.
You'll have to clone the original object. This is because storing the object in another variable doesn't create a new object with the same properties as the previous one; it just creates a reference to the same object. Sadly, there aren't any built in solutions to get around this, but there are a few solutions. Here some that come to mind:
var temp = JSON.parse(JSON.stringify(data)); // clones the object using a hack
Or:
var temp = {}; // creates a new object and gives it all the same properties as
// the old one.
for(prop in data) {
if(data.hasOwnProperty(prop)) {
temp[prop] = data[prop];
}
}
Not to be self-promoting, but I've written up a blog post about this subject which goes into a little more detail. You can find here.
Assigning an object to a variable does not make a copy of the object. It just creates another reference to the same object. Both variables will then point to the exact same object and changing properties of either one (data and temp in your example) will change the exact same object.
To make a copy of an object, one has to actually make an explicit copy of the object by copying all the properties to a new object.
You can use the clone method of the underscore library to easily clone an object.
var temp = _.clone(data);