Clone object which have function stored inside - javascript

After cloning object with JSON.parse(JSON.stringify(object)) function which was stored inside first object is not cloned to second one:
obj1: {
first: true,
second: function() { return 'test';}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
After cloning obj2 has only first property in itself and looks like this:
obj2: {
first: true
}
Is there a way to clone function property also?

Including a function in an object turns it into a JavaScript object rather than a JSON object, as JSON does not allow the use of functions as property values.
You try this
obj2 = { ...obj1 };
you can also use a library like lodash to deep clone your object and use it as
const _ = required('lodash');
obj2 = _.cloneDeep(obj1);

Functions cannot be encoded into JSON.
You can use the spread syntax for a shallow clone:
let obj1 = {a: 10, b: () => "test"};
let obj2 = {...obj1};
// obj2: {a: 10, b: () => "test"}
Note that this is a shallow clone. So suppose you have some other property c in obj1 that is an object, this code will not clone c. Rather it will just point obj2.c to the the same object as obj1.c.

Related

Modifying the cloning array should not affect the changes to parent array in javascript [duplicate]

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

How to copy js object that contains function

I have issues with copying my object that has a function in itself. see below code and afterwards explanation of issue.
const obj1 = {...object1};
const obj2 = {...object2};
const obj3 = {...object3};
const parentObj = {
id: "123",
name: "foo",
nestedObj: [obj1, obj2, obj3],
somefunc(){
return obj1.value + obj2.value + obj3.value
}
}
My way of copying this object...
const copyObj = {
...parentObj,
nestedObj: parentObj.nestedObj.map(obj=>{
return{
...obj
}
})
}
The issue with above is the following:
I have a form-control that allows me to change obj1, obj2 or obj3 value key.
This "new" value that is being assigned to the nested object, is needed for the function.
However when being copied, my function is always using the original value of the nestedObj.
Is there a way for me to bind the function the the newly copied parentObj?
If somefunc is called like copyObj.somefunc() such that the this value corresponds to the object you call the method on, then it will work when you define somefunc as follows:
somefunc(){
return this.nestedObj.reduce((sum, obj) => sum + obj.value, 0);
}
So if now nestedObj has the objects you really want to use, then somefunc will produce the expected sum, provided it is called on the right container object.

JS how to deep copy two objects [duplicate]

This question already has answers here:
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 1 year ago.
I have an obj1:
const obj1 = { val: {v: 0}}
I'm trying to deep copy it by doing:
const obj2 = {...obj1}
However the {v: 0} is still not copied, how would I do this>
I guess this is the easiest way, but a bit clumsy
const obj2 = JSON.parse(JSON.stringify(obj1))
Otherwise you need to write a recursive cloning function or use some library - just search for cloneDeep, copyDeep or smth along these lines.
You can use lodash-es package for this. It provides the function cloneDeep() that will recursively clone values.
Here is the package: https://www.npmjs.com/package/lodash-es
Here are the Docs: https://lodash.com/docs/4.17.15#cloneDeep
import { cloneDeep as _cloneDeep } from 'lodash-es';
const obj2 = _cloneDeep(obj1);
You are doing it how you should (with the spread operator). The spread operator will copy everything just fine.
const obj1 = { val: {v: 0} };
const obj2 = { ...obj1 };
console.log(obj2);
const obj1 = {
test: 1,
test2: {
t: 1,
f: () => console.log('hello')
}
};
const obj2 = { ...obj1 };
console.log( obj2 );
console.log( obj2.test2.f() );
If you were to (at any time) do a JSON.stringify on the object, you will lost any methods/functions or other things that don't translate to the json scheme so it's best to avoid doing that. Object destructuring is what you want.
I don't have enough rep to even flag but this is a cleeeeeear duplicate of a lot of questions
even googling the title would have been easier for you
anyway I use a module called rfdc that does just that, and lodash has a function to do it to
otherwise you can loop through your src object with a recursive function that adds fields to your dest object

Is destructing assigning in JavaScript shallow or deep copy?

I'm confused by the destructing assigning in JavaScript about shallow and deep copy. For example,
const obj = {key:{}, value:{}}
let {key} = obj
key = {msg: 'hello'}
Is the value of key in the sample above a shallow or deep copy of the key in obj? What is the value of key should be?
let {key} = obj
… is the same as saying:
let key = obj.key
It is a shallow copy.
key = {msg: 'hello'}
… overwrites the reference to the object that also exists in obj.key with a reference to a new object.
This renders the previous line pointless as nothing was done with the value before it was overwritten.
It's shallow, though there's some nuance.
This:
let {key} = obj;
has exactly the same result as this:
let key = obj.key;
E.g., all it does is copy the value of obj.key into key, making both of them point to the same object — a shallow copy, if the word "copy" really applies. (Normally I think of a "shallow copy" as copying multiple properties, not just one, like Object.assign does.)
You can reach deeper into the object graph you're retrieving from by using nested destructuring:
const obj = {
a: {
b: {
c: {
d: "hi",
},
},
},
};
const {a: {b: {c}}} = obj;
console.log(c.d); // "hi"
but at the end of the day it's just like an assignment, so it's just grabbing the object reference (if the value is an object reference), not a copy of the object:
const obj = {
a: {
b: {
c: {
d: "hi",
},
},
},
};
const {a: {b: {c}}} = obj;
console.log(c.d); // "hi"
console.log(obj.a.b.c.d); // "hi"
c.d = c.d.toLocaleUpperCase();
console.log(c.d); // "HI"
console.log(obj.a.b.c.d); // "HI"
But, even if it were a deep copy, your code still wouldn't change anything in obj, because you're changing the value of what's in key (an object reference), not the state of the object that reference refers to. After let {key} = obj, key is completely disconnected from obj.key other than that they both refer to the same object. If you change the value in key, the variable, it has no effect on the object it refers to. If you're goign to do key = ..., there's no point to let {key} = obj at all, just use let key.

Adding objects to an object property which is an object itself with object assign

so say I have this:
const mainObject = {
prop1: false,
prop2: {} or []
}
const minorObject = { name: "name", address: "address" }
const minorObject2 = {name: "name2", address: "address2" }
how do add them one at time to mainObject.prop2 without mutating mainObject with Object.assign, if it is not possible then how can it be done with ES6 spread?
When you want to keep the main reference immutable you need to work with shallow copies, similar to what happen when you work with primitives.
An example with Strings (when literally declared they are treated as primitives):
var a = 'Hello';
var b = a;
b += ' World';
console.log({a, b});
As you can see, mutating b the variable a remains immutable... this because primitives are passed by value.
Because Object is not a primitive it is passed by reference and the above example becomes:
var a = { prop: 'Hello' };
var b = a;
b.prop += ' World';
console.log({a, b});
how do add them one at time to mainObject.prop2 without mutating mainObject ...?
var a = { prop: 'Hello' }
var minorA = { prop1: ' World' };
var minorB = { prop2: ' Moon' };
var b = Object.assign({}, a); //create a shallow copy
Object.assign(b, minorA, minorB)
// because you can pass as many params you want, you can simplify the previous code in this way:
var b = Object.assign({}, a, minorA, minorB);
how can it be done with ES6 spread?
The Object spread operator, that is in esnext, you can use it with babel and Object rest spread transform
var b = {...a};
Object.assign will mutate the object passed as the first argument, so if you want to combine the properties of two objects without mutating either, simply wrap one Object.assign inside another.
Object.assign(Object.assign({},mainObject),minorObject)
How to push elements of an object into another object?
Add Javascript Object into another Javascript Object
google keyword search =
add an object to another object
plenty of more examples out there and ways of going about it.

Categories