9.6 Use cases for Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() helps us with two use cases, if we combine it with Object.defineProperties() or Object.create().

9.6.1 Use case: copying properties into an object

Since ES6, JavaScript already has had a tool method for copying properties: Object.assign(). However, this method uses simple get and set operations to copy a property whose key is key:

  1. target[key] = source[key];

That means that it only creates a faithful copy of a property if:

  • Its attribute writable is true and its attribute enumerable is true (because that’s how assignment creates properties).
  • It is a data property.

The following example illustrates this limitation. Object source has a setter whose key is data.

  1. const source = {
  2. set data(value) {
  3. this._data = value;
  4. }
  5. };
  6. // Because there is only a setter, property `data` exists,
  7. // but has the value `undefined`.
  8. assert.equal('data' in source, true);
  9. assert.equal(source.data, undefined);

If we use Object.assign() to copy property data, then the accessor property data is converted to a data property:

  1. const target1 = {};
  2. Object.assign(target1, source);
  3. assert.deepEqual(
  4. Object.getOwnPropertyDescriptor(target1, 'data'),
  5. {
  6. value: undefined,
  7. writable: true,
  8. enumerable: true,
  9. configurable: true,
  10. });
  11. // For comparison, the original:
  12. const desc = Object.getOwnPropertyDescriptor.bind(Object);
  13. assert.deepEqual(
  14. Object.getOwnPropertyDescriptor(source, 'data'),
  15. {
  16. get: undefined,
  17. set: desc(source, 'data').set,
  18. enumerable: true,
  19. configurable: true,
  20. });

Fortunately, using Object.getOwnPropertyDescriptors() together with Object.defineProperties() does faithfully copy the property data:

  1. const target2 = {};
  2. Object.defineProperties(
  3. target2, Object.getOwnPropertyDescriptors(source));
  4. assert.deepEqual(
  5. Object.getOwnPropertyDescriptor(target2, 'data'),
  6. {
  7. get: undefined,
  8. set: desc(source, 'data').set,
  9. enumerable: true,
  10. configurable: true,
  11. });
9.6.1.1 Pitfall: copying methods that use super

A method that uses super is firmly connected with its home object (the object it is stored in). There is currently no way to copy or move such a method to a different object.

9.6.2 Use case for Object.getOwnPropertyDescriptors(): cloning objects

Shallow cloning is similar to copying properties, which is why Object.getOwnPropertyDescriptors() is a good choice here, too.

To create the clone, we use Object.create():

  1. const original = {
  2. set data(value) {
  3. this._data = value;
  4. }
  5. };
  6. const clone = Object.create(
  7. Object.getPrototypeOf(original),
  8. Object.getOwnPropertyDescriptors(original));
  9. assert.deepEqual(original, clone);

For more information on this topic, see §6 “Copying objects and Arrays”.