ES6, ES2015 : Object.assign

You probably know underscore or lodash extend method (at leat lodash right)? Like most of these utilities functions, those are deprecated by an ES6 (ES2015) feature.

#Object.assign

The new static method Object.assign take a bunch of objects as arguments :

  • The first is a target for copies;
  • Next are sources;
  • All own properties (enumerable keys and non inherited, even those which are undefined) will be copied in the target (so last ones take precedences);
  • The target object is modified (it must be mutable);
  • The modified target object is returned.
const o = { y: 0 }
const o1 = { x: 1, y: 2 }
const o2 = { x: undefined, z: 3 }
Object.assign(o, o1, o2) // { x: undefined, y: 2, z: 3 }
o // { x: undefined, y: 2, z: 3 }
o1 // unmodified
o2 // unmodified

#Becareful to mutability

Be warned that the target is always modified. Since the most frequent use-case is the creation of a new object that will be generated from others sources, most of the time we will pass an new empty object as the first parameter.

const o1 = { x: 1 }
const o2 = { y: 2 }
const o = Object.assign({}, o1, o2)
o // { x: 1, y: 2 }
// o1 and o2 are unmodified

#Specific use-cases

#Error during the copy

If a property in the target is read-only, Object.assign should behave like in strict mode (unlike the wtf mode) and throw an error before stoping the copy.

const o = Object.create({}, {
  val: { value: 42, enumerable: true, writable: false }
})

// "standard" (wtf) mode:
o.val = 0 // no error
o.val // 42 (unmodified value)
Object.assign(o, { x: 1, val: 0, y: 2 }) // Uncaught TypeError: Cannot assign…
o // { val: 42, x: 1 }

// "strict" mode:
o.val = 0 // Uncaught TypeError: Cannot assign…
Object.assign(o, { x: 1, val: 0, y: 2 }) // Uncaught TypeError: Cannot assign…
o // { val: 42, x: 1 }

Keys that have already been copied before the throwing of the exception will be kept in the target object, that's why in our example x have been copied but not y.

Note: this is theory, but practise show us that this behavior is variable, depending of the platform and the context, the error might not always be thrown. To get a predictable behavior, you should work in strict mode.

#Scalar sources

When sources are scalar values (number, boolean, etc) Object.keys will not return any keys and values will be ignored. null and undefined will also be ignored.

Particular case: strings are treated as array.

const o = {}
Object.assign(o, 1, true, null, "toto", ["b", "a"], undefined)
// 1, true, null, undefined are ignored
// "toto" is converted to {0: "t", 1: "o", 2: "t", 3: "o"}
// ["b", "a"] is converted to {0: "b", 1: "a"}
o // {0: "b", 1: "a", 2: "t", 3: "o"}

#Conclusion

We can forget _.clone, _.extend and friends with this method!

About compatiblity, Object.assign is pretty well supported by all modern browsers (IE is not considered as modern until 12) :

  • Edge (IE ≥ 12) ;
  • Chrome stable (46) ;
  • Firefox stable (42) ;
  • Node ≥ 4 ;
  • If you need to support old browsers, you will need Babel or one of many users implementations.

Written by naholyr

Associate in ByteClub, developer, consultant, trainer, around modern JavaScript technologies (ES6, Node, React…).Regular open-source contributor, blog posts author, and speaker. Said shortly: passionate :)

Be the first to contribute to this page