Simplifying the Object.assign Method in JavaScript
Take a deep dive into the JavaScript language by exploring the ins and outs of the Object.assign( ) method.
Join the DZone community and get the full member experience.
Join For FreeIn JavaScript, an object's assign method copies the source object’s own enumerable properties to a target object and returns that target object.
There are two important keywords in the above sentence:
- Enumerable
- Own
Before we go ahead and understand the purpose of Object.assign, it is essential that we really understand these two words, enumerable properties and own properties. Let's examine them one by one.
A JavaScript object could have either enumerable or non-enumerable properties. However, by default, when you create a property on an object, it is enumerable. Enumerable means you can enumerate through those properties. Let's understand it through code.
const babycat = {
age: '1',
color: 'white'
}
for (var prop in babycat) {
console.log(prop);
}
There are two properties in babycat
object. By default, both are enumerable, hence. as the output of the for...in loop, you will get both the age and name printed.
Now let us change the default enumerable behavior of the age property using the Object.defineProperty
method.
const babycat = {
age: '1',
color: 'white'
}
Object.defineProperty(babycat, 'age', { enumerable: false });
for (var prop in babycat) {
console.log(prop);
}
We have changed the enumerable of the age property to false, so, as an output, only the color will be printed. Hence, age is no longer an enumerable property of the babycat
object.
Another keyword in the above sentence is own properties. To understand it, you need to understand the object prototype chain. All JavaScript objects are part of a prototype chain and thus can access properties of its prototype. So, own properties are those properties which are particular to the object and not from the prototype chain. Let's look at own properties through some code examples:
const cat = {
name: 'foo'
}
const babycat = {
age: '1',
color: 'white'
}
//babycat.__proto__ = cat; // I love this more
Object.setPrototypeOf(babycat, cat);
for (var prop in babycat) {
console.log(prop);
}
In the above code snippet, there are two objects, cat
and babycat
. In addition, the [[Prototype]] property of the babycat
object is set to the cat
object. When you print the properties of the babycat
object using a for...in loop, output age, color, and name will be printed, as shown in the below image:
What is happening here? Well, JavaScript prints all the properties from the prototype chain. However, only age and color are own properties of the babycat
object.
Now that we've gone over own properties and enumerable properties the in context of a JavaScript object, let us revisit the first statement of this post: In JavaScript, an object’s assign method copies the source object’s own enumerable properties to a target object and returns that target object.
Consider the code below:
const cat = {
name: 'foo'
}
const babycat = Object.assign({}, cat);
for (var prop in babycat) {
console.log(prop + ':' + babycat[prop]);
}
Using the Object.assign()
method, we are copying the cat
object's own enumerable properties to the babycat
object. Here, the cat
object is the source and the babycat
object is the target. You will get the output printed as below:
The Object.assign()
method uses [[Get]] on the source object and [[set]] on the target object and invokes setters and getters to perform the task. Essentially, it assigns property values from the source to the target object. It does not create a new property in the target object.
Let us examine some variations while copying properties from the source object to a target object.
Same Properties in Both Target and Source Objects
If the target object has the same properties as the source object, then Object.assign()
method will override target object properties. Consider the code below:
const cat = {
name: 'foo',
age: 9
}
const babycat = Object.assign({ age: 1 }, cat);
for (var prop in babycat) {
console.log(prop + ':' + babycat[prop]);
}
There is an age property in both the target object and source object. While copying the properties in the target object, the Object.assign()
method will override the target object's age property. Thus, you will get the output shown in the below image:
Deep Cloning of Objects
As we saw in pervious examples, cloning can be performed using the Object.assign()
method. To refresh, the below code snippet performs the cloning.
const cat = {
name: 'foo',
age: 9
}
const babycat = Object.assign({}, cat);
for (var prop in babycat) {
console.log(prop + ':' + babycat[prop]);
}
The Object.assign()
method copies values. Thereforthe e, if source object has a reference type, it will copy the reference value. Let us understand it through code:
const cat = {
name: 'foo',
age: 9,
child: {
nochild: 2
}
}
const babycat = Object.assign({}, cat);
console.log(cat.name); // foo
console.log(babycat.name); // foo
console.log(cat.child.nochild); // 2
console.log(babycat.child.nochild); // 2
babycat.name = 'koo';
babycat.child.nochild = 9;
console.log(cat.name); // foo
console.log(babycat.name); // koo
console.log(cat.child.nochild); // 9
console.log(babycat.child.nochild); // 9
In the above example, the Object.assign
method will copy:
- The value of
name
andage
. - The value of the
child
reference, as it is of reference type.
Since, for the name
property, only the value is copied, when you change its value in the babycat
object, it does not affect the cat
object’s name property. However, when you change the value of the child
property on the babycat
object, it changes the value of the cat
object also, because of its reference type nature. As expected, when you run the above sample, you will get an output as shown below:
Merging More Than One Source Object
Using the Object.assign()
method, you can also merge more than one object to a target object. Consider the code listed below:
const obj1 = {
a: 1
}
const obj2 = {
b: 2
}
const obj3 = {
c: 3
}
const obj4 = Object.assign({}, obj1, obj2, obj3, { d: 4 });
for (let p in obj4) {
console.log(obj4[p]);
}
We are merging obj1
, obj2
, obj3
, and the unnamed object to target, obj4
. You will get the output printed below:
Null and Undefined
JavaScript's Object.assign()
method ignores null and undefined while copying objects. Consider the code listed below:
const obj1 = {
a: 1
}
const obj2 = Object.assign({}, obj1, null, undefined, { d: 4 });
for (let p in obj2) {
console.log(obj2[p]);
}
As output, you will get 1 and 4 printed because the assign
method ignores undefined and null.
You should use JavaScript's Object.assign()
method to copy the source object’s own enumerable properties to the target object. It does clone objects, by copying the value from the source object.
Published at DZone with permission of Dhananjay Kumar, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments