扩展对象时使用`super()`

时间:2018-07-20 09:24:41

标签: javascript ecmascript-6

我正在创建一个在JavaScript中扩展Object的类,并期望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

在此示例中,为什么foo不在'bar'上定义为ext

编辑

说明Using `super()` when extending `Object`

解决方案Using `super()` when extending `Object`

3 个答案:

答案 0 :(得分:11)

实际上没有人解释为什么它不起作用。如果我们查看at the latest spec,则Object函数的定义如下:

  

19.1.1.1对象([值])

     

使用可选参数Object调用value函数时,将执行以下步骤:

     
      
  1. 如果NewTarget既不是undefined也不是活动函数,则      
        
    1. 返回? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%")
    2.   
  2.   
  3. 如果valuenullundefined或未提供,请返回ObjectCreate(%ObjectPrototype%)
  4.   
  5. 返回! ToObject(value)
  6.   

第一步很重要: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);

换句话说:Object不会复制传入对象的属性,而只是按原样返回对象。因此,扩展Object也不会复制属性。

答案 1 :(得分:5)

您缺少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

答案 2 :(得分:5)

此答案仅在使用Babel编译器时有效。

因为对象的构造函数返回值。参见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