Getter / Setter 和原型链

Getter / Setter and Prototype Chain

在当前使用 ES6 class 语法和 get/set 语法的 JavaScript 项目中,我偶然发现了一个我无法解释的行为。

首先,一个按预期工作的提取演示:

class A {
    constructor() {
        this.__value = null;
    }

    get value() {
        return this.__value;
    }

    set value(value) {
        this.__value = value;
    }
}

class B extends A { }

let b = new B();
b.value = 2;
console.log(b.value); // output: 2

设置和获取 b.value(在 A.prototype 中定义)有效。

现在考虑以下演示,其中我仅将 setter 从 A 移动到 B:

class A {
    constructor() {
        this.__value = null;
    }

    get value() {
        return this.__value;
    }
}

class B extends A {
    set value(value) {
        this.__value = value;
    }
}

let b = new B();
b.value = 2;          // b.__value is 2
console.log(b.value); // output: undefined

设置值有效(因为b.__value确实是2),但是getter似乎不​​存在,尽管它仍然在A.prototype中定义。

这里有什么问题?

当您尝试检索 属性,而 属性 不在实例上时,引擎将首先查找 [=38] 的原型链=] 链中的对象,它有一个 属性 描述符用于 属性 问题。当找到所述描述符时,如果它有一个 getter,则调用 getter。否则,如果没有 getter,它将检索 属性 的普通值,如果有

在第二种情况下,属性 描述符在 B.prototype 上。但是 B.prototype 没有 value 的 getter (B.prototype 也没有 value 的普通值)!所以,undefined 是 returned.

如果 B.prototype 有 getter 用于 value,它将被调用:

'use strict';

class A {
    constructor() {
        this.__value = null;
    }

    get value() {
        return this.__value;
    }
}

class B extends A {
    set value(value) {
        this.__value = value;
    }
    get value() {
        console.log('trying to get value');
    }
}

let b = new B();
b.value = 2;
b.value;

但它没有。引擎不会继续在原型链中向上寻找 getter - 相反,它会停止并 return undefined,因为没有 getter(或纯值) 在原型链中的第一个对象上找到 hasOwnProperty('value').

如果您有一个 getter,并且您希望能够设置相同的 属性,则 setter 必须与 getter 在同一对象上,反之亦然。