JavaScript 覆盖原型方法

JavaScript overwrite prototype method

考虑以下代码:

class X {
  pop() { return 'ORIGINAL'; }
}

const x = new X();

x.pop(); // 'ORIGINAL' via prototype lookup

x.pop = () => 'NEW'; // install a new pop()

x.pop(); // 'NEW' calls x's pop()

Object.getOwnPropertyDescriptors(x); // has NEW pop
Object.getOwnPropertyDescriptors(Object.getPrototypeOf(x)); // has ORIGINAL pop

调用 pop 时,原型查找会找到原始 pop。为什么分配不覆盖那个而不是在 x 上安装 NEW pop

如果我明确地 X.prototype.pop = () => 'NEW'; 它会起作用。

当您将方法分配给一个对象时,该方法将被放置在您在分配中指定的精确对象上。所以,当你这样做时:

x.pop = () => 'NEW';

您正在将 属性 分配给值为函数的对象实例 x。该对象的原型完全不受此分配的影响。

当你在一个对象上执行一个方法时,解释器有一个查找序列来找到那个方法。首先,它直接查看对象以查看 属性 是否存在。如果它找到它,那就是执行。

因此,当您执行以下操作时:

x.pop()

在上一次赋值之后,解释器找到分配给实际对象的方法并执行那个方法。

在您执行该方法分配之前,当您执行 x.pop() 时,在实际对象实例上找不到该名称的 method/property,因此解释器将查看是否存在原型如果存在,则搜索原型链。这就是它从 class 定义中找到 .pop() 并执行该定义的地方。

这些是单独的定义,存储在不同的地方,改变一个不会改变另一个定义。尽管将特定 属性 的定义分配给对象实例本身往往会“隐藏”原型上的定义,因为在分配后您可以访问原型上的定义的唯一方法是直接引用prototype 因为通过对象实例本身对 属性 的任何引用都会首先在对象实例本身上找到它(因此不再自动找到原型上的那个)。