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 因为通过对象实例本身对 属性 的任何引用都会首先在对象实例本身上找到它(因此不再自动找到原型上的那个)。
考虑以下代码:
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 因为通过对象实例本身对 属性 的任何引用都会首先在对象实例本身上找到它(因此不再自动找到原型上的那个)。