Consider the below code or check this fiddle.
var obj = {
name: "abc",
age: 20
}
var objTwo;
console.log(obj.age);
objTwo = obj;
objTwo.age = 10;
console.log(obj.age);
I have created an object with name obj and it has two properties. Now I assign obj to another object named objTwo. Now I update one of the properties in objTwo. The same change is reflecting on obj as well. How can I assign values from one object to another without creating reference?
JavaScript provides 3 good ways to clone objects: using spread operator, rest operator and Object. assign() function. Aside from just cloning objects, using object spread and Object. assign() lets you add or updated properties when creating the clone.
The javaScript, generally, we have used some default method/function to achieve. The goal for these types of concepts is called cloning the object, but each and every function has its own attributes and properties in the script.
Spread operation is the easiest way to clone a object in ES6. Data loss happens on this method as well. However, since this is native to ES6 it is more performant than JSON. strigify().
Copy an Object With Object.assign() was the most popular way to deep copy an object. Object. assign() will copy everything into the new object, including any functions. Mutating the copied object also doesn't affect the original object.
this will assign not by reference
<script>
var obj =
{
name: 'abc',
age: '30'
};
var objTwo = {};
for( var i in obj )
{
objTwo[i] = obj[i];
}
</script>
view fiddle
I would use jQuery to do this:
var obj1 = {
name: "abc",
age: 20
}
console.log(obj1);
var obj2 = $.extend({}, obj1, {});
console.log(obj2);
obj2.age = 1;
console.log(obj2);
console.log(obj1);
If you only need to clone simple objects, simply doing
JSON.parse (JSON.stringify (obj))
would suffice.
But this obviously doesn't work in all cases, since JSON.stringify
can't handle circular references and strips out functions.
So if you want to go beyond that, things will get more complicated and you have to either rely on some utility library or need to implement your own deep clone method.
Here is a sample implementation that expects a level of deepness to clone.
(function (Object, Array) {
function cloneObject(deep, scope, clonedScope) {
var type = typeof this,
clone = {},
isCR = -1;
deep = Number(deep) || 0;
scope = scope || [];
clonedScope = clonedScope || [];
if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
throw new TypeError("Unexpected input");
}
//If we find a primitive, we reeturn its value.
if (type !== "object") {
return this.valueOf();
}
scope.push(this);
clonedScope.push(clone);
if (0 === deep) { //If we reached the recursion limit, we can perform a shallow copy
for (var prop in this) {
clone[prop] = this[prop];
}
} else { //Otherwise we need to make some checks first.
for (var prop in this) {
if ((isCR = scope.indexOf(this[prop])) > -1) { //If we find a circular reference, we want create a new circular reference to the cloned version.
clone[prop] = clonedScope[isCR];
} else if (typeof this[prop] !== "undefined" && this[prop] !== null) { //Otherwise continue cloning.
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone(deep - 1, scope, clonedScope)); //If we find a non object, we can directly assign it. Otherwise we need to recursively call the clone function, counting down the limit, and injecting the scopeArrays, to find circular references.
} else { //If the property is undefined or null, assign it as such.
clone[prop] = this[prop];
}
}
}
scope.pop(); //If we leave a recursion leve, we remove the current object from the list.
clonedScope.pop();
return clone;
}
function cloneArray(deep, scope, clonedScope) {
var clone = [];
deep = Number(deep) || 0;
scope = scope || [];
clonedScope = clonedScope || [];
if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
throw new TypeError("Unexpected input");
}
scope.push(this);
clonedScope.push(this);
if (0 === deep) clone = this.concat();
else this.forEach(function (e) {
if ((isCR = scope.indexOf(e)) > -1) {
clone.push(clonedScope[isCR]);
} else if (typeof e !== "undefined" && e !== null) {
clone.push((typeof e !== "object" ? e : e.clone(deep - 1, scope, clonedScope)));
} else {
clone.push(e);
}
});
scope.pop();
clonedScope.pop();
return clone;
}
Object.defineProperty(Object.prototype, "clone", {
enumerable: false,
value: cloneObject
});
Object.defineProperty(Array.prototype, "clone", {
enumerable: false,
value: cloneArray
});
})(Object, Array);
Note that extending the the built-ins prototypes is often frowned upon, however i decided to do it that way to avoid an additional typecheck and to split the logic for arrays and objects a bit more. This can easily be refactored to a normal function instead
Some tests to check that we indeed have new references.
var first = {
a: {
b: "b",
c: {
}
},
b: "asd",
c: [{}],
d: undefined,
e: null,
f: function a() {} //functions keep their original reference..
};
first.a.c.a = first.a; //Circular object reference
first.c.push(first.c); //Circular array reference
var second = first.clone(Infinity);
console.log(second, second.a === second.a.c.a, first.a !== second.a.c.a); //..., true, true.
There may be a lot of space for improvement, I particularily don't like how the scope and clonedScope get's injected. If anyone has an better idea of finding and reattaching circular references, i'd be glad to update the answer
Here is a Fiddle as well.
var obj, objTwo;
obj = {
name: "abc",
age: 20
}
console.log(obj.age);
objTwo = copy(obj);
objTwo.age = 10;
console.log(obj.age);
function copy (obj) {
var key, rtn = Object.create(Object.getPrototypeOf(obj));
for (key in obj) {
if (obj.hasOwnProperty(key)) {
rtn[key] = obj[key];
}
}
return rtn;
}
In javascript everything is passed by reference. The reason the modification "leaks" to the original function property (variable), is because you are modifying the object's property, not the object (reference) itself. Copy the object to another variable, instead of re-assigning it.
Off-topic:
In javascript everything is passed by reference. apparently is a bit contested; That's why I'm adding this addendum. Feel free to correct me if I'm wrong.
Is JavaScript a pass-by-reference or pass-by-value language? The top answer states it most clearly:
Instead, the situation is that the item passed in is passed by value. But the item that is passed by value is itself a reference.
So my wording was confusing, but if you also keep in my mind that every operator returns a reference, and keep in mind that every assignment and parameter-passing simply copies those references returned by operators (and value-literals), then passed-by-reference kind of makes sense.
The linked top answer has the full (correct) explanation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With