Categories
Modern JavaScript

Best Features of ES2018 — Object Spread vs Object.assign

Spread the love

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at the best features of ES2018.

Cloning Object Prototype with Properties

We can clone the object’s prototype with properties.

To do that, we can set the __proto__ property to the original object’s prototype:

const obj = {
  a: 1,
  b: 2
};

const clone = {
  __proto__: Object.getPrototypeOf(obj),
  ...obj
};

We set the prototype and we spread the other properties to get a more comprehensive clone.

This is the same as:

const clone = Object.assign(
  Object.create(Object.getPrototypeOf(obj)), obj);

Merging Two Objects

The object spread operator is also handy for merging multiple objects into one.

For instance, we can write:

const merged = {
  ...obj1,
  ...obj2
};

which is the same as:

const merged = Object.assign({}, obj1, obj2);

Merging objects is useful for doing things like merging options with the default options:

const data = {
  ...DEFAULTS,
  ...options
};

Spreading Objects versus Object.assign()

The spread operator and Object.assign are very similar.

The difference is that spread define new properties, while Object.assign set them.

For instance, if we have:

Object.assign(target, obj1, obj2);

then target is modified in place with the properties of obj1 and obj2 .

If we want to create a new merged object with the properties from all 3 objects, we can write:

const merged = Object.assign({}, target, obj1, obj2);

It returns a new object with the properties from target , obj1 , and obj2 .

The spread operator is the same as the 2nd way of using Object.assign .

Spread and Object.assign both read values with a get operation.

For instance, if we have:

const obj = {
  get a() {
    return 1
  }
}

const clone = Object.assign({}, obj);

Then the a getter is cloned in clone .

If we have:

const obj = {
  get a() {
    return 1
  }
}

const clone = {
  ...obj
};

Then we get the same result.

The spread operator defines new properties in the target object.

But Object.assign uses a normal set operation to create them.

If we add a setter to the Object.prototype , create the object, and run Object.assign on it:

Object.defineProperty(Object.prototype, 'foo', {
  set(value) {
    console.log('set', value);
  },
});

const obj = {
  foo: 1
};

const clone = `Object.assign({}, obj);`

then the setter is run as we can see from the console log.

On the other hand, if we have:

Object.defineProperty(Object.prototype, 'foo', {
  set(value) {
    console.log('set', value);
  },
});
const obj = {
  foo: 1
};

const clone = {
  ...obj
}

then the setter isn’t run.

With Object.assign , we can stop it from creating non-inherited properties via inherited read-only properties.

For instance, we can write:

Object.defineProperty(Object.prototype, 'foo', {
    writable: false,
    value: 1,
});

const obj = {
  foo: 1
};

const clone = Object.assign({}, obj);

Then we get ‘Uncaught TypeError: Cannot assign to read-only property ‘foo’ of object ‘#<Object>’’.

On the other hand, if we have:

Object.defineProperty(Object.prototype, 'foo', {
  writable: false,
  value: 1,
});

const obj = {
  foo: 1
};
const clone = {
  ...obj
};

Then we don’t get any errors, so the property is rated successfully.

This is because the spread operator defines properties rather than setting them.

Conclusion

Object.assign does similar things, but there are small differences that we can’t overlook.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *