【问题标题】:Using `super()` when extending `Object`扩展 `Object` 时使用 `super()`
【发布时间】:2018-07-20 09:24:41
【问题描述】:

我正在创建一个在 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

为什么在这个例子中ext 上的foo 没有定义为'bar'

编辑

解释Using `super()` when extending `Object`

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

【问题讨论】:

  • 虽然我不能回答你的问题,但我不禁想知道你为什么还要extend Object
  • 因为我希望扩展类的实例与 Object 的行为相同,并具有自定义功能。我明白你的意思,因为我猜想在不扩展 Object 并在构造函数中使用 Object.assign() 时可以创建相同的功能,正如 Gildas.Tambo 所建议的那样。但这真的让我想知道为什么它不以这种方式工作..
  • 这个问题的有趣之处在于 Babel 可以转译这段代码以给出正确的结果
  • 问题就是问题。 没有理由为什么它应该包含指向答案的链接。您可以通过接受将答案置顶,仅此而已。

标签: javascript ecmascript-6


【解决方案1】:

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

19.1.1.1 对象([值])

当使用可选参数value调用Object函数时,将采取以下步骤:

  1. 如果NewTarget既不是undefined也不是活动函数,那么
    1. 返回 ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%")
  2. 如果valuenullundefined 或未提供,则返回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);

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

【讨论】:

  • 太好了,终于明白为什么使用Object.create()只能和Object做同样的工作,而不能添加extend方法。
【解决方案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

【讨论】:

  • 虽然这可行,但在这种情况下我们不需要extends Objectsuper(),对吧?我想这更像是“复制”父母(对象)构造方法的来源?
  • 是的,因为我们正在处理对象,请尝试使用 super developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…了解 ECMAScript 6 类和继承以及超类调用
  • @TimBaas 我对此表示怀疑......假设你删除了 extends Objectsuper(...args) ,一切正常......它只是在复制价值。
【解决方案3】:

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

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

【讨论】:

  • @barbsan 这不是一个有效的答案,您正在使用 babel 转译代码,这就是它起作用的原因,在本机支持 ES6 的浏览器中,这不起作用
  • @Caramiriel 那是因为您在构造函数中返回了一个新对象:{foo:'bar'}。在 barbsan 的回答中,super() 被返回,它不是一个新对象,而是这个类的一个新实例。
  • @Caramiriel 因为我在 sn-p 的设置中选择了 Babel 转译器
猜你喜欢
  • 2019-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-16
  • 1970-01-01
  • 1970-01-01
  • 2019-02-17
相关资源
最近更新 更多