Использование 'super()' при расширении 'Object'

Я создаю класс, который расширяет Object в JavaScript и ожидает, что super() инициализирует ключи/значения при создании нового экземпляра этого класса.

class ExtObject extends Object {
  constructor(...args) {
    super(...args);
  }
}

const obj = new Object({foo:'bar'});
console.log(obj); // { foo: 'bar' }

const ext = new ExtObject({foo:'bar'});
console.log(ext); // ExtObject {}

console.log(ext.foo); // undefined

Ответ 1

Никто на самом деле не объяснил, почему это не работает. Если мы посмотрим на последнюю спецификацию, функция Object определяется следующим образом:

19.1.1.1 Объект ([значение])

Когда вызывается функция Object с дополнительным value, выполняются следующие шаги:

  1. Если NewTarget является ни undefined ни активной функцией, тогда
    1. Вернуть? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
  2. Если value равно null, undefined или не ObjectCreate(%ObjectPrototype%), верните ObjectCreate(%ObjectPrototype%).
  3. Вернуть ! ToObject(value).

Первый шаг - важный здесь: NewTarget ссылается на функцию, которую вызывали new. Поэтому, если вы создадите new Object, это будет Object. Если вы new ExtObject это будет ExtObject.

Поскольку ExtObject не является Object ("ни активная функция"), условие соответствует, а OrdinaryCreateFromConstructor оценивается и возвращается его результат. Как вы можете видеть, ничего не делается со value переданным функции.

value используется, только если ни 1., ни 2. не выполняются. И если value является объектом, оно просто возвращается как есть, новый объект не создается. Таким образом, new Object(objectValue) фактически совпадает с Object(objectValue):

var foo = {bar: 42};
console.log(new Object(foo) === foo);
console.log(Object(foo) === foo);

Ответ 2

Вам не хватает Object.assign

class ExtObject extends Object {
  constructor(...args) {
    super(...args);
    Object.assign(this, ...args);
  }
}

const obj = new Object({foo:'bar'});
console.log(obj); // { foo: 'bar' }

const ext = new ExtObject({foo:'bar'});
console.log(ext); // { foo: 'bar' }

console.log(ext.foo); // bar

Ответ 3

Этот ответ работает только при использовании транспондера Babel.

Поскольку Object constructor возвращает значение. См. Spec

15.2.2.1 новый объект ([значение])
Когда конструктор Object вызывается без аргументов или с одним значением аргумента, предпринимаются следующие шаги:
...
8. Возвращает obj.

class ExtObject extends Object {
  constructor(...args) {
    return super(...args);
  }
}

const obj = new Object({foo:'bar'});
console.log(obj); // { foo: 'bar' }

const ext = new ExtObject({foo:'bar'});
console.log(ext); // { foo: 'bar' }

console.log(ext.foo); // bar