首页 > 解决方案 > JavaScript 错误属性在一个实例和它的原型中是不同的——怎么会这样?

问题描述

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

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" ]

fileName, lineNumber,怎么可能columnNumber存在于实例上,但如果实例刚刚被创建并且没有以任何方式改变,那么原型上不存在?

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

标签: javascriptoopprototypeprototype-chain

解决方案


fileName, lineNumber, columnNumber 怎么可能存在于实例上,但如果实例刚刚创建且未以任何方式更改,则原型上不存在?

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

例子:

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

const err = new Error();

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

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

不应该是不可能的吗?我的意思是,我希望新创建的实例具有与原型完全相同的属性。

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

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

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

另外,实例没有堆栈作为自己的属性,是因为它是不可枚举的吗?

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

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


推荐阅读