Related
I am copying objA to objB
const objA = { prop: 1 },
const objB = objA;
objB.prop = 2;
console.log(objA.prop); // logs 2 instead of 1
same problem for Arrays
const arrA = [1, 2, 3],
const arrB = arrA;
arrB.push(4);
console.log(arrA.length); // `arrA` has 4 elements instead of 3.
It is clear that you have some misconceptions of what the statement var tempMyObj = myObj; does.
In JavaScript objects are passed and assigned by reference (more accurately the value of a reference), so tempMyObj and myObj are both references to the same object.
Here is a simplified illustration that may help you visualize what is happening
// [Object1]<--------- myObj
var tempMyObj = myObj;
// [Object1]<--------- myObj
// ^
// |
// ----------- tempMyObj
As you can see after the assignment, both references are pointing to the same object.
You need to create a copy if you need to modify one and not the other.
// [Object1]<--------- myObj
const tempMyObj = Object.assign({}, myObj);
// [Object1]<--------- myObj
// [Object2]<--------- tempMyObj
Old Answer:
Here are a couple of other ways of creating a copy of an object
Since you are already using jQuery:
var newObject = jQuery.extend(true, {}, myObj);
With vanilla JavaScript
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var newObject = clone(myObj);
See here and here
deep clone object with JSON.parse() and JSON.stringify
// Deep Clone
obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
refrence: this article
Better reference: this article
To sum it all up, and for clarification, there's four ways of copying a JS object.
A normal copy. When you change the original object's properties, the copied object's properties will change too (and vice versa).
const a = { x: 0}
const b = a;
b.x = 1; // also updates a.x
A shallow copy. Top level properties will be unique for the original and the copied object. Nested properties will be shared across both objects though. Use the spread operator ...{} or Object.assign().
const a = { x: 0, y: { z: 0 } };
const b = {...a}; // or const b = Object.assign({}, a);
b.x = 1; // doesn't update a.x
b.y.z = 1; // also updates a.y.z
A deep copy. All properties are unique for the original and the copied object, even nested properties. For a deep copy, serialize the object to JSON and parse it back to a JS object.
const a = { x: 0, y: { z: 0 } };
const b = JSON.parse(JSON.stringify(a));
b.y.z = 1; // doesn't update a.y.z
A full deep copy. With the above technique, property values that are not valid in JSON (like functions) will be discarded. If you need a deep copy and keep nested properties that contain functions, you might want to look into a utility library like lodash.
import { cloneDeep } from "lodash";
const a = { x: 0, y: { z: (a, b) => a + b } };
const b = cloneDeep(a);
console.log(b.y.z(1, 2)); // returns 3
Using Object.create() does create a new object. The properties are shared between objects (changing one also changes the other). The difference with a normal copy, is that properties are added under the new object's prototype __proto__. When you never change the original object, this could also work as a shallow copy, but I would suggest using one of the methods above, unless you specifically need this behaviour.
Try using the create() method like as mentioned below.
var tempMyObj = Object.create(myObj);
This will solve the issue.
Try using $.extend():
If, however, you want to preserve both of the original objects, you
can do so by passing an empty object as the target:
var object = $.extend({}, object1, object2);
var tempMyObj = $.extend({}, myObj);
use three dots to spread object in the new variable
const a = {b: 1, c: 0};
let d = {...a};
As I couldn't find this code anywhere around suggested answers for shallow copy/cloning cases, I'll leave this here:
// shortcuts
const {
create,
getOwnPropertyDescriptors,
getPrototypeOf
} = Object;
// utility
const shallowClone = source => create(
getPrototypeOf(source),
getOwnPropertyDescriptors(source)
);
// ... everyday code ...
const first = {
_counts: 0,
get count() {
return ++this._counts;
}
};
first.count; // 1
const second = shallowClone(first);
// all accessors are preserved
second.count; // 2
second.count; // 3
second.count; // 4
// but `first` is still where it was
first.count; // just 2
The main difference compared to Object.assign or {...spread} operations, is that this utility will preserve all accessors, symbols, and so on, in the process, including the inheritance.
Every other solution in this space seems to miss the fact cloning, or even copying, is not just about properties values as retrieved once, but accessors and inheritance might be more than welcome in daily cases.
For everything else, use native structuredClone method or its polyfill 👋
This might be very tricky, let me try to put this in a simple way. When you "copy" one variable to another variable in javascript, you are not actually copying its value from one to another, you are assigning to the copied variable, a reference to the original object. To actually make a copy, you need to create a new object use
The tricky part is because there's a difference between assigning a new value to the copied variable and modify its value. When you assign a new value to the copy variable, you are getting rid of the reference and assigning the new value to the copy, however, if you only modify the value of the copy (without assigning a new value), you are modifying the copy and the original.
Hope the example helps!
let original = "Apple";
let copy1 = copy2 = original;
copy1 = "Banana";
copy2 = "John";
console.log("ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); // Apple
console.log(copy1); // Banana
console.log(copy2); // John
//----------------------------
original = { "fruit" : "Apple" };
copy1 = copy2 = original;
copy1 = {"animal" : "Dog"};
copy2 = "John";
console.log("\n ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); //{ fruit: 'Apple' }
console.log(copy1); // { animal: 'Dog' }
console.log(copy2); // John */
//----------------------------
// HERE'S THE TRICK!!!!!!!
original = { "fruit" : "Apple" };
let real_copy = {};
Object.assign(real_copy, original);
copy1 = copy2 = original;
copy1["fruit"] = "Banana"; // we're not assiging a new value to the variable, we're only MODIFYING it, so it changes the copy and the original!!!!
copy2 = "John";
console.log("\n MODIFY the variable without assigning a new value to it, also changes the original variable")
console.log(original); //{ fruit: 'Banana' } <====== Ops!!!!!!
console.log(copy1); // { fruit: 'Banana' }
console.log(copy2); // John
console.log(real_copy); // { fruit: 'Apple' } <======== real copy!
If you have the same problem with arrays then here is the solution
let sectionlist = [{"name":"xyz"},{"name":"abc"}];
let mainsectionlist = [];
for (let i = 0; i < sectionlist.length; i++) {
mainsectionlist[i] = Object.assign({}, sectionlist[i]);
}
In Javascript objects are passed as reference and they using shallow comparison so when we change any instance of the object the same changes is also referenced to the main object.
To ignore this replication we can stringify the JSON object.
example :-
let obj = {
key: "value"
}
function convertObj(obj){
let newObj = JSON.parse(obj);
console.log(newObj)
}
convertObj(JSON.stringify(obj));
The following would copy objA to objB without referencing objA
let objA = { prop: 1 },
let objB = Object.assign( {}, objA )
objB.prop = 2;
console.log( objA , objB )
You can now use structuredClone() for deep object clones :
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
const newItem = structuredClone(oldItem);
Serialize the original object into JSON and Deserialize to another object variable of same type. This will give you copy of object with all property values. And any modification to original object will not impact the copied object.
string s = Serialize(object); //Serialize to JSON
//Deserialize to original object type
tempSearchRequest = JsonConvert.DeserializeObject<OriginalObjectType>(s);
I am copying objA to objB
const objA = { prop: 1 },
const objB = objA;
objB.prop = 2;
console.log(objA.prop); // logs 2 instead of 1
same problem for Arrays
const arrA = [1, 2, 3],
const arrB = arrA;
arrB.push(4);
console.log(arrA.length); // `arrA` has 4 elements instead of 3.
It is clear that you have some misconceptions of what the statement var tempMyObj = myObj; does.
In JavaScript objects are passed and assigned by reference (more accurately the value of a reference), so tempMyObj and myObj are both references to the same object.
Here is a simplified illustration that may help you visualize what is happening
// [Object1]<--------- myObj
var tempMyObj = myObj;
// [Object1]<--------- myObj
// ^
// |
// ----------- tempMyObj
As you can see after the assignment, both references are pointing to the same object.
You need to create a copy if you need to modify one and not the other.
// [Object1]<--------- myObj
const tempMyObj = Object.assign({}, myObj);
// [Object1]<--------- myObj
// [Object2]<--------- tempMyObj
Old Answer:
Here are a couple of other ways of creating a copy of an object
Since you are already using jQuery:
var newObject = jQuery.extend(true, {}, myObj);
With vanilla JavaScript
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var newObject = clone(myObj);
See here and here
deep clone object with JSON.parse() and JSON.stringify
// Deep Clone
obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
refrence: this article
Better reference: this article
To sum it all up, and for clarification, there's four ways of copying a JS object.
A normal copy. When you change the original object's properties, the copied object's properties will change too (and vice versa).
const a = { x: 0}
const b = a;
b.x = 1; // also updates a.x
A shallow copy. Top level properties will be unique for the original and the copied object. Nested properties will be shared across both objects though. Use the spread operator ...{} or Object.assign().
const a = { x: 0, y: { z: 0 } };
const b = {...a}; // or const b = Object.assign({}, a);
b.x = 1; // doesn't update a.x
b.y.z = 1; // also updates a.y.z
A deep copy. All properties are unique for the original and the copied object, even nested properties. For a deep copy, serialize the object to JSON and parse it back to a JS object.
const a = { x: 0, y: { z: 0 } };
const b = JSON.parse(JSON.stringify(a));
b.y.z = 1; // doesn't update a.y.z
A full deep copy. With the above technique, property values that are not valid in JSON (like functions) will be discarded. If you need a deep copy and keep nested properties that contain functions, you might want to look into a utility library like lodash.
import { cloneDeep } from "lodash";
const a = { x: 0, y: { z: (a, b) => a + b } };
const b = cloneDeep(a);
console.log(b.y.z(1, 2)); // returns 3
Using Object.create() does create a new object. The properties are shared between objects (changing one also changes the other). The difference with a normal copy, is that properties are added under the new object's prototype __proto__. When you never change the original object, this could also work as a shallow copy, but I would suggest using one of the methods above, unless you specifically need this behaviour.
Try using the create() method like as mentioned below.
var tempMyObj = Object.create(myObj);
This will solve the issue.
Try using $.extend():
If, however, you want to preserve both of the original objects, you
can do so by passing an empty object as the target:
var object = $.extend({}, object1, object2);
var tempMyObj = $.extend({}, myObj);
use three dots to spread object in the new variable
const a = {b: 1, c: 0};
let d = {...a};
As I couldn't find this code anywhere around suggested answers for shallow copy/cloning cases, I'll leave this here:
// shortcuts
const {
create,
getOwnPropertyDescriptors,
getPrototypeOf
} = Object;
// utility
const shallowClone = source => create(
getPrototypeOf(source),
getOwnPropertyDescriptors(source)
);
// ... everyday code ...
const first = {
_counts: 0,
get count() {
return ++this._counts;
}
};
first.count; // 1
const second = shallowClone(first);
// all accessors are preserved
second.count; // 2
second.count; // 3
second.count; // 4
// but `first` is still where it was
first.count; // just 2
The main difference compared to Object.assign or {...spread} operations, is that this utility will preserve all accessors, symbols, and so on, in the process, including the inheritance.
Every other solution in this space seems to miss the fact cloning, or even copying, is not just about properties values as retrieved once, but accessors and inheritance might be more than welcome in daily cases.
For everything else, use native structuredClone method or its polyfill 👋
This might be very tricky, let me try to put this in a simple way. When you "copy" one variable to another variable in javascript, you are not actually copying its value from one to another, you are assigning to the copied variable, a reference to the original object. To actually make a copy, you need to create a new object use
The tricky part is because there's a difference between assigning a new value to the copied variable and modify its value. When you assign a new value to the copy variable, you are getting rid of the reference and assigning the new value to the copy, however, if you only modify the value of the copy (without assigning a new value), you are modifying the copy and the original.
Hope the example helps!
let original = "Apple";
let copy1 = copy2 = original;
copy1 = "Banana";
copy2 = "John";
console.log("ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); // Apple
console.log(copy1); // Banana
console.log(copy2); // John
//----------------------------
original = { "fruit" : "Apple" };
copy1 = copy2 = original;
copy1 = {"animal" : "Dog"};
copy2 = "John";
console.log("\n ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); //{ fruit: 'Apple' }
console.log(copy1); // { animal: 'Dog' }
console.log(copy2); // John */
//----------------------------
// HERE'S THE TRICK!!!!!!!
original = { "fruit" : "Apple" };
let real_copy = {};
Object.assign(real_copy, original);
copy1 = copy2 = original;
copy1["fruit"] = "Banana"; // we're not assiging a new value to the variable, we're only MODIFYING it, so it changes the copy and the original!!!!
copy2 = "John";
console.log("\n MODIFY the variable without assigning a new value to it, also changes the original variable")
console.log(original); //{ fruit: 'Banana' } <====== Ops!!!!!!
console.log(copy1); // { fruit: 'Banana' }
console.log(copy2); // John
console.log(real_copy); // { fruit: 'Apple' } <======== real copy!
If you have the same problem with arrays then here is the solution
let sectionlist = [{"name":"xyz"},{"name":"abc"}];
let mainsectionlist = [];
for (let i = 0; i < sectionlist.length; i++) {
mainsectionlist[i] = Object.assign({}, sectionlist[i]);
}
In Javascript objects are passed as reference and they using shallow comparison so when we change any instance of the object the same changes is also referenced to the main object.
To ignore this replication we can stringify the JSON object.
example :-
let obj = {
key: "value"
}
function convertObj(obj){
let newObj = JSON.parse(obj);
console.log(newObj)
}
convertObj(JSON.stringify(obj));
The following would copy objA to objB without referencing objA
let objA = { prop: 1 },
let objB = Object.assign( {}, objA )
objB.prop = 2;
console.log( objA , objB )
You can now use structuredClone() for deep object clones :
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
const newItem = structuredClone(oldItem);
Serialize the original object into JSON and Deserialize to another object variable of same type. This will give you copy of object with all property values. And any modification to original object will not impact the copied object.
string s = Serialize(object); //Serialize to JSON
//Deserialize to original object type
tempSearchRequest = JsonConvert.DeserializeObject<OriginalObjectType>(s);
Let's say I have class called Person, which have firstName, lastName, and Array of addresses fields.
And in one of my angular components I am getting Person object to do some operation on them. But I would like to create two copies of this obj. To do that I am using Object.assign. But after that when I am manipulating firstName from firstCopyPerson all other objects are changed too.
How can I assign object to new variable without making reference to orginal object, but instead just creating new separate object?
mainPerson: Person;
firstCopyPerson: Person;
secondCopyPerson: Person;
ngOnInit() {
this.mainPerson = someCache.getPerson();
this.firstCopyPerson: Object.assign({}, this.mainPerson);
this.secondCopyPerson: Object.assign({}, this.mainPerson);
}
You can add this re-usable function so you can reuse this function everytime
const copyObject = (obj) => {
let result = {};
Object.entries(obj).forEach(([key, value]) => {
result[key] = value;
});
return result;
};
// Test the function
const obj1 = {name: 'notebook', price: 100};
objCopy = copyObject(obj1);
console.log(objCopy);
You can also use this way
const obj = {name: 'laptop', price: 100};
// This is the implementation line
let objCopy = {...obj};
console.log(objCopy);
whenever you use this code you are assigning a new reference to the object and both variables assigning to the same object so when you edit one of them the other will change too. you can solve this by destructing the object for example you can try this :
let personCopy = {...person}
Object.assign would only make a shallow copy of the object, that means all attributes are assigned to the same data objects.
You may want to read about deep copies which are the safe way to go.
Fenton already posted a brilliant answer to this, take a look at option 4 in his answer:
https://stackoverflow.com/a/28152032/8341158
I am copying objA to objB
const objA = { prop: 1 },
const objB = objA;
objB.prop = 2;
console.log(objA.prop); // logs 2 instead of 1
same problem for Arrays
const arrA = [1, 2, 3],
const arrB = arrA;
arrB.push(4);
console.log(arrA.length); // `arrA` has 4 elements instead of 3.
It is clear that you have some misconceptions of what the statement var tempMyObj = myObj; does.
In JavaScript objects are passed and assigned by reference (more accurately the value of a reference), so tempMyObj and myObj are both references to the same object.
Here is a simplified illustration that may help you visualize what is happening
// [Object1]<--------- myObj
var tempMyObj = myObj;
// [Object1]<--------- myObj
// ^
// |
// ----------- tempMyObj
As you can see after the assignment, both references are pointing to the same object.
You need to create a copy if you need to modify one and not the other.
// [Object1]<--------- myObj
const tempMyObj = Object.assign({}, myObj);
// [Object1]<--------- myObj
// [Object2]<--------- tempMyObj
Old Answer:
Here are a couple of other ways of creating a copy of an object
Since you are already using jQuery:
var newObject = jQuery.extend(true, {}, myObj);
With vanilla JavaScript
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var newObject = clone(myObj);
See here and here
deep clone object with JSON.parse() and JSON.stringify
// Deep Clone
obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
refrence: this article
Better reference: this article
To sum it all up, and for clarification, there's four ways of copying a JS object.
A normal copy. When you change the original object's properties, the copied object's properties will change too (and vice versa).
const a = { x: 0}
const b = a;
b.x = 1; // also updates a.x
A shallow copy. Top level properties will be unique for the original and the copied object. Nested properties will be shared across both objects though. Use the spread operator ...{} or Object.assign().
const a = { x: 0, y: { z: 0 } };
const b = {...a}; // or const b = Object.assign({}, a);
b.x = 1; // doesn't update a.x
b.y.z = 1; // also updates a.y.z
A deep copy. All properties are unique for the original and the copied object, even nested properties. For a deep copy, serialize the object to JSON and parse it back to a JS object.
const a = { x: 0, y: { z: 0 } };
const b = JSON.parse(JSON.stringify(a));
b.y.z = 1; // doesn't update a.y.z
A full deep copy. With the above technique, property values that are not valid in JSON (like functions) will be discarded. If you need a deep copy and keep nested properties that contain functions, you might want to look into a utility library like lodash.
import { cloneDeep } from "lodash";
const a = { x: 0, y: { z: (a, b) => a + b } };
const b = cloneDeep(a);
console.log(b.y.z(1, 2)); // returns 3
Using Object.create() does create a new object. The properties are shared between objects (changing one also changes the other). The difference with a normal copy, is that properties are added under the new object's prototype __proto__. When you never change the original object, this could also work as a shallow copy, but I would suggest using one of the methods above, unless you specifically need this behaviour.
Try using the create() method like as mentioned below.
var tempMyObj = Object.create(myObj);
This will solve the issue.
Try using $.extend():
If, however, you want to preserve both of the original objects, you
can do so by passing an empty object as the target:
var object = $.extend({}, object1, object2);
var tempMyObj = $.extend({}, myObj);
use three dots to spread object in the new variable
const a = {b: 1, c: 0};
let d = {...a};
As I couldn't find this code anywhere around suggested answers for shallow copy/cloning cases, I'll leave this here:
// shortcuts
const {
create,
getOwnPropertyDescriptors,
getPrototypeOf
} = Object;
// utility
const shallowClone = source => create(
getPrototypeOf(source),
getOwnPropertyDescriptors(source)
);
// ... everyday code ...
const first = {
_counts: 0,
get count() {
return ++this._counts;
}
};
first.count; // 1
const second = shallowClone(first);
// all accessors are preserved
second.count; // 2
second.count; // 3
second.count; // 4
// but `first` is still where it was
first.count; // just 2
The main difference compared to Object.assign or {...spread} operations, is that this utility will preserve all accessors, symbols, and so on, in the process, including the inheritance.
Every other solution in this space seems to miss the fact cloning, or even copying, is not just about properties values as retrieved once, but accessors and inheritance might be more than welcome in daily cases.
For everything else, use native structuredClone method or its polyfill 👋
This might be very tricky, let me try to put this in a simple way. When you "copy" one variable to another variable in javascript, you are not actually copying its value from one to another, you are assigning to the copied variable, a reference to the original object. To actually make a copy, you need to create a new object use
The tricky part is because there's a difference between assigning a new value to the copied variable and modify its value. When you assign a new value to the copy variable, you are getting rid of the reference and assigning the new value to the copy, however, if you only modify the value of the copy (without assigning a new value), you are modifying the copy and the original.
Hope the example helps!
let original = "Apple";
let copy1 = copy2 = original;
copy1 = "Banana";
copy2 = "John";
console.log("ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); // Apple
console.log(copy1); // Banana
console.log(copy2); // John
//----------------------------
original = { "fruit" : "Apple" };
copy1 = copy2 = original;
copy1 = {"animal" : "Dog"};
copy2 = "John";
console.log("\n ASSIGNING a new value to a copied variable only changes the copy. The ogirinal variable doesn't change");
console.log(original); //{ fruit: 'Apple' }
console.log(copy1); // { animal: 'Dog' }
console.log(copy2); // John */
//----------------------------
// HERE'S THE TRICK!!!!!!!
original = { "fruit" : "Apple" };
let real_copy = {};
Object.assign(real_copy, original);
copy1 = copy2 = original;
copy1["fruit"] = "Banana"; // we're not assiging a new value to the variable, we're only MODIFYING it, so it changes the copy and the original!!!!
copy2 = "John";
console.log("\n MODIFY the variable without assigning a new value to it, also changes the original variable")
console.log(original); //{ fruit: 'Banana' } <====== Ops!!!!!!
console.log(copy1); // { fruit: 'Banana' }
console.log(copy2); // John
console.log(real_copy); // { fruit: 'Apple' } <======== real copy!
If you have the same problem with arrays then here is the solution
let sectionlist = [{"name":"xyz"},{"name":"abc"}];
let mainsectionlist = [];
for (let i = 0; i < sectionlist.length; i++) {
mainsectionlist[i] = Object.assign({}, sectionlist[i]);
}
In Javascript objects are passed as reference and they using shallow comparison so when we change any instance of the object the same changes is also referenced to the main object.
To ignore this replication we can stringify the JSON object.
example :-
let obj = {
key: "value"
}
function convertObj(obj){
let newObj = JSON.parse(obj);
console.log(newObj)
}
convertObj(JSON.stringify(obj));
The following would copy objA to objB without referencing objA
let objA = { prop: 1 },
let objB = Object.assign( {}, objA )
objB.prop = 2;
console.log( objA , objB )
You can now use structuredClone() for deep object clones :
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
const newItem = structuredClone(oldItem);
Serialize the original object into JSON and Deserialize to another object variable of same type. This will give you copy of object with all property values. And any modification to original object will not impact the copied object.
string s = Serialize(object); //Serialize to JSON
//Deserialize to original object type
tempSearchRequest = JsonConvert.DeserializeObject<OriginalObjectType>(s);
Does this code mutate the object or is volatile in any other way?
How can I avoid it if it does?
const object = {property: false};
const test = {property: !object.property};
Your code doesn't mutate anything. When you create test, the original object is not affected as .property is a boolean (and hence value type), so your new assignment is by value only.
const test = {property: !object.property}; // assigns a new value to a new reference
This, on the other hand does:
const object = {property: false};
object.property = !object.property; // mutating the object
const test = object; // copying the reference
You could do this, though:
const object = {property: false};
const test = {...object, property: !object.property}; // creates a copy of object and over-writes the value of the new property