JavaScript 实例及其原型中的错误属性不同 - 怎么会这样?

JavaScript Error properties are different in an instance and its prototype - how so?

我不明白错误属性是如何定义的。有些是在实例上定义的,有些是在原型上定义的。不应该是不可能的吗?我的意思是,我希望新创建的实例具有与原型完全相同的属性。这就是我的意思:

let err = new Error('Test');

Object.getOwnPropertyNames(err);
// Array(4) [ "fileName", "lineNumber", "columnNumber", "message" ]

Object.getOwnPropertyNames(Object.getPrototypeOf(err));
// Array(5) [ "toString", "message", "name", "stack", "constructor" ]

fileNamelineNumbercolumnNumber 怎么可能存在于实例上,但不存在于原型上,如果实例刚刚创建且未更改有什么办法吗?

另外,实例本身没有stack 属性,是不是因为它是不可枚举的?

How is it possible that fileName, lineNumber, columnNumber exist on the instance, but do not exist on the prototype if it the instance just been created and not altered in any way?

这里没有什么神奇的事情发生。 Error 是构造函数。该函数可以在实例上创建任何属性。

示例:

class Error {
  constructor() {
    this.fileName = '<script>';
  }
}

const err = new Error();

console.log(Object.getOwnPropertyNames(err));
console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(err)));

如您所见,fileName是一个只存在于实例上的属性。

Shouldn't it be impossible? I mean, I would expect that a freshly created instance would have exactly the same properties as the prototype.

这不是它应该的工作方式。原型包含应该在 所有实例 共享 的属性,并且实例包含特定于该实例的属性。最后,原型只是另一个对象(实例)指向的对象。它仅在访问实例上的 属性 时使用。如果 属性 在实例上不存在,JS 运行时将在实例的原型等上查找它。仅此而已。

也许您在实例和原型上看到 message 会感到惊讶。原型上的 message 属性 是默认的错误信息。如果错误实例没有自己的消息,则使用它(如果你没有将参数传递给 Error 构造函数,错误实例 not 有自己的 message 属性(参见 the spec))。

const err = new Error();
console.log(Object.getOwnPropertyNames(err));
console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(err)));

Also, the instance does not have stack as its own property, is it because it's non-enumerable?

不,“自己的”属性 是“自己的”属性,无论其可枚举性如何。 stack 是一个 getter/setter,因此它可以通过 this 在当前实例上运行(或者该功能是为本机函数实现的)。

console.log(Object.getOwnPropertyDescriptor(Error.prototype, 'stack'));
// Object { get: stack(), set: stack(), enumerable: false, configurable: true }