在下面,我尝试创建一个 Object 的子类,其行为类似于 Object 在使用“new”创建实例方面的行为。我当然会向我的子类添加更多方法,但下面显示了我从构造函数中调用超级构造函数的问题。
为什么我的类 Sub 的实例不像普通对象那样具有字段“x”,当以相同的方式使用“new”和相同的参数创建时?
class Sub extends Object
{ constructor (anObject)
{ super(anObject);
}
}
var ob = new Object ({x: 123} );
var sub = new Sub ({x: 123} );
console.log( ob.x ); // -> 123
console.log( sub.x); // -> undefined
基本上,因为
Object
很特殊并且遵循不同的规则,因为它几乎是 JavaScript 中最基本的构造。
无需扩展
Object
,只需创建不带超类的对象(因为它无论如何都是一个对象)并使用 Object.assign(this, obj)
将所有属性分配给新创建的对象。
class Sub {
constructor(obj) {
Object.assign(this, obj);
}
}
console.log(new Object({a: 1}));
console.log(new Sub({a: 1}));
虽然我发现这种行为让自己感到困惑(因此无法回答更深层次的“为什么这样设计”),但它似乎是记录在案的行为。在 MDN 中写道:
当在继承 Object 的类的构造函数中通过 super() 隐式调用 Object() 时,它会初始化一个以 new.target.prototype 作为原型的新对象。传递给 super() 的任何值都会被忽略 - 例如,即使您传递一个数字,构造函数内的 this 值也不会成为 Number 实例。
规格说:
该函数在调用时执行以下步骤:
- 如果 NewTarget 既不是未定义的也不是活动函数对象,那么 A。返回 ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%").
- 如果 value 未定义或为 null,则返回 OrdinaryObjectCreate(%Object.prototype%)。
- 归来! ToObject(值)。
据我了解,虽然最后一个是您拨打
new Object(obj)
时得到的,但您在拨打super(obj)
时得到第一个。
因此,这种行为不仅存在于 Node 中,而且存在于所有符合浏览器规范的浏览器中(我已在 Firefox 115 和 Chromium 115 中进行了验证)。