【问题标题】:cannot understand the Javascript setter and getter lookup in classes无法理解类中的 Javascript setter 和 getter 查找
【发布时间】:2021-01-10 04:52:54
【问题描述】:

我知道 JavaScript 类是原型的语法糖,在其他 OOP 语言中不能作为纯类工作。但是这里出现的问题是在 getter 和 setter 上。当完全将 getter 和 setter 留在子类中时,它的行为正常,但如果我定义了任何一个 getter 或 setter,就会破坏这些。

例如:

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

    set value(value) {
        console.log("setter called")
        this.__value = value;
    }
    
    get value() {
        console.log("getter called")
        return this.__value;
    }
}

class B extends A {
    
}

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

上面的代码工作正常,但如果我在子类中定义 getter 或 setter,则查找不会转到父类。我用谷歌搜索了一下,发现这是故意的,而且是 ES 标准。那为什么当子类没有方法时,查找到父类并且能够访问getter和setter?

【问题讨论】:

    标签: javascript prototype getter-setter


    【解决方案1】:

    当您访问对象属性时,无论是设置值obj.prop = 'val' 还是检索值console.log(obj.prop),引擎都会尝试在对象的原型链中查找该属性。

    它从实例开始。在这种情况下,实例没有任何属性,所以它会继续。

    下一个对象是实例的内部原型,即B.prototype。如果B 有正在查看的属性名称,它将停在那里。如果有一个设置器,并且为属性分配了一个值,则将调用该设置器。如果有 getter,并且正在检索的值,则将调用 getter。

    就是这样 - 一旦在原型链中找到一个属性,它就会停止搜索。

    如果B.prototype 没有setter/getter,那么引擎将继续执行next 对象。 B.prototype的内部原型是A.prototype。然后,A 的 setter 或 getter 将被调用。

    可以从子类调用超类的setter/getter,但是看起来有点奇怪:

    class A {
        constructor() {
            this.__value = "Default";
        }
    
        set value(value) {
            console.log("setter called")
            this.__value = value;
        }
        
        get value() {
            console.log("getter called")
            return this.__value;
        }
    }
    
    class B extends A {
        set value(value) {
            console.log('sub setter calling super');
            super.value = value;
        }
        get value() {
            console.log('sub getter calling super');
            return super.value;
        }
    }
    
    let b = new B();
    b.value = 2;
    console.log(b.value);

    【讨论】:

    • 这是否特定于 (get 和 set) 之类的访问器,因为其他方法查找工作得很好?
    • 不,同样的事情适用于所有属性。例如,如果实例有{ prop: 'foo' }B.prototype{ prop: 'bar' },你尝试访问instance.prop,你会得到foo;一旦找到链中具有该属性的第一个对象,引擎就会停止查找。
    • 是的,我按照自己的方式重新创建后就明白了。看看这个小提琴jsfiddle.net/dr03v2zg
    【解决方案2】:

    在谷歌搜索和大量代码执行之后,我找到了我自己问题的答案,如果我们在子类中没有定义访问器(getter 或 setter),则查找将继续向父类进行,但如果我们使用 @987654321 设置任何访问器@ 或 set 子类中的描述符,它将调用 Object.defineProperty 方法并设置我们提到的描述符。如果我们有 setter 和 getter 没有问题,但是如果我们留下任何一个导致这些属性丢失我们当前的对象。这就是我们得到undefined 的原因,因为未定义的属性得到了undefined 值。所以从字面上看,我们找到了undefined 的值,这是我们不能继续将父原型作为值(@ 987654327@) 在当前对象中找到,查找将停止。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-09
      • 2018-12-08
      • 1970-01-01
      相关资源
      最近更新 更多