2014-01-08

ECMAScript 6: merging objects via Object.assign()

Copying all properties of one object to another one is a common operation in JavaScript. This blog post explains ECMAScript 6’s implementation of it, which is called Object.assign().

This merging operation has a name in the JavaScript ecosystem that is only used there (and, unfortunately, clashes with classic OOP terminology): “extend”. Two examples of “extend” being provided by libraries:

Object.assign()

For merging objects, ECMAScript 6 will have the function
    Object.assign(target, source_1, ..., source_n)
This function modifies target and returns it: it first copies all enumerable [1] own operties of source_1 to target, then those of source_2, etc.

Property keys: either strings or symbols

In ECMAScript 6, property keys can be either strings or symbols. The latter are a new kind of unique identifier; there are never any name clashes with symbols as keys. Object.assign() supports both strings and symbols as keys.

Copying versus assignment

Properties in the target object are created via assignment (internal operation [[Put]]). That means that if target has (own or inherited) setters [1], those will be invoked during copying. An alternative would have been to define new properties [2], an operation which always creates new own properties and never invokes setters. There originally was a proposal for a variant of Object.assign() that uses definition instead of assignment. That proposal has been rejected for ECMAScript 6 (but may be reconsidered for later editions).

Use cases for Object.assign()

Setting up instance properties

The task of a constructor is to set up instance properties. Alas, variable names are always mentioned redundantly for this task:
    class Point {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }
    }
My favorite would have been the following syntax to completely remove that redundancy (CoffeeScript and TypeScript both have ways of doing this, but I prefer this syntax):
    class Point {
        constructor(this.x, this.y) {
        }
    }
Object.assign() at least enables you to avoid some of the redundancy:
    class Point {
        constructor(x, y) {
            Object.assign(this, { x, y });
        }
    }
In ECMAScript 6, { x, y } is an abbreviation for { x: x, y: y }.

Adding a method to an object

ECMAScript 5, you use a function expression to add a method to an object:
    MyClass.prototype.foo = function (arg1, arg2) {
        ...
    };
ECMAScript 6 has a more concise syntax for methods [3]. Thanks to Object.assign(), you don’t have to abandon that syntax:
    Object.assign(MyClass.prototype, {
        foo(arg1, arg2) {
            ...
        }
    });

Cloning an object

You can also use Object.assign() to (shallowly) clone an object:
    var copy = Object.assign({ __proto__: obj.__proto__ }, obj);
If you are only interested in an object’s own properties, things become simpler:
    var copy = Object.assign({}, obj);

References

  1. Object properties in JavaScript
  2. Properties in JavaScript: definition versus assignment
  3. Callable entities in ECMAScript 6

No comments: