Simplifying Object.assign Method in JavaScript

Dhananjay Kumar / Monday, December 31, 2018

“In JavaScript, Object’s assign method copies source object’s own enumerable properties to a target object, and returns that target object “

There are two important keywords in the above sentence:

  1. Enumerable
  2. Own

Before we go ahead and understand purpose of Object.assign, it is essential that we really understand these two words, enumerable properties and own properties.  Let us see them one by one:

A JavaScript object could have either enumerable or non-enumerable properties. However, by default when you create property on an object, it is enumerable.  Enumerable  means you can enumerate through those properties. Let us 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 for..in loop, you will get both age and name printed.

 Now let us change default enumerable behavior of age property using 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 enumerable of age property to false, so as output, you will get only color printed. Hence, age is no longer an enumerable property of babycat object.

 Another keyword in above sentence is own properties. To understand it, you need to understand object prototype chain. All JavaScript objects are part of a prototype chain, hence can access properties of its prototype’s also.  So, own properties are those properties, which are particular to the object and not from the prototype chain.  Let us understand own properties through 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 above code snippet, there are two objects cat and babycat. In addition, [[Prototype]] property of babycat object is set to cat object. When you print properties of the babycat object using for..in loop, you will find as output age, color, name printed as shown in below image:

 What is happening here? Well, JavaScript prints all properties from the prototype chain. However, only age and color are, own properties of babycat object. As of now, you should have understood own properties and enumerable properties in context of a JavaScript object.   So let us revisit first statement of this post,

“In JavaScript, Object’s assign method copies source object’s own enumerable properties to a target object, and returns that target object “ . You should able to infer what exactly above sentence implies.  Consider code below :  

const cat = {
 
    name: 'foo'
}
 
const babycat = Object.assign({}, cat);
 
for (var prop in babycat) {
    console.log(prop + ':' + babycat[prop]);
}

Using Object.assign() method , we are copying cat object own enumerable properties to babycat object. Here, cat object is source and babycat object is target. You will get output printed as below:

The Object.assign() method uses [[Get]] on the source object and [[set]] on the target object and invokes setter and getter to perform the task. Essentially, it assigns properties values from source to target object. It does not create new property in the target object. As of now you know purpose of the Object.assign() method. Let us examine some variations while copying properties from source object to a target object.

Same Properties in Both Target and Source Object

If target object has same properties as of source object, then Object.assign() method will  override target object properties.  To understand it consider code listing 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 age property in both target object and source object.  While copying properties in target object the Object.assign() method will override target object age property, hence you will get output as shown in the below image :

Deep Cloning of Objects

As we saw in pervious examples that, using the Object.assign() method cloning can be performed. To refresh, below code snippet perform 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() copies values. Therefore, if source object has a reference type, it will copy 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 above example, the Object.assign will copy

  • Value of name and age
  • Value of reference of child as it is of reference type.

Since for name property only value is copied, when you change its value in babycat object, it does not affect cat object’s name property. However, when you change value of child property on the babycat object, it changes value of cat object also because of its reference type nature.  As expected when you run above sample, you will get output as shown in the image below:

Merging More than One Source Objects

 Using Object.assign() method you can also merge more than one objects to a target object. Consider 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 unnamed object to target object obj4.  You will get output printed as below:

Null and Undefined

 JavaScript Object.assign() method ignores null and undefined while copying objects. Consider 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 assign method ignores undefined and null.

You should use JavaScript Object.assign() method to copy source object’s own enumerable properties to target object. It does clone objects, by copying value from the source object.