为什么在JavaScript中(super .__ proto__ === this .__ proto__)是正确的?


10

似乎在JavaScript(ES6)类中super.__proto__ === this.__proto__

您能解释为什么会这样吗?在不同的浏览器上,行为似乎是一致的,因此我怀疑这是在规范中的某个地方指定的。

考虑以下代码:

class Level1 {
    myFunc() {
        console.log('Level1');
    }
}

class Level2 extends Level1 {
    myFunc() {
        console.log('Level2');
    }
}

class Level3 extends Level2 {
    myFunc() {
        console.log('Level3 BEGIN ' + Math.random()); 
        super.__proto__.myFunc();
        console.log(super.__proto__ === this.__proto__);
        console.log('Level3 END'); 
    }
}

const foo = new Level3();
foo.myFunc();

我本来希望super.__proto__.myFunc();可以调用myFunc()class Level1和that 的功能super.__proto__ !== this.__proto__。相反,super.__proto__.myFunc();实际上是调用myFunc()class Level3(它自己调用),然后在第二次调用时调用myFunc()class Level2。如果super.__proto__ === this.__proto__代码演示的话,这是完全可以理解的。

您能否解释super.__proto__ === this.__proto__此示例中的原因?如果可能的话,还请提供对规范相关部分的引用。

Answers:


6

Object.prototype.__proto__是具有吸气剂的属性[1]。它以其this价值为基础。没有实际的super对象是一个this值(您不能编写Object.getPrototypeOf(super)),只是一种super查找属性的方法,因此this.__proto__super.__proto__只要__proto__没有在原型链的任何下方进行定义,就意味着同一件事。

相比:

class Parent {
    get notProto() {
        return this instanceof Child;
    }
}

class Child extends Parent {
    test() {
        console.log(super.notProto);
    }
}

new Child().test();

// bonus: [1]
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));


我已经怀疑这与__proto__实际使用访问器函数Object.prototype并按其this值进行操作有关。但是我只是无法想象super实际上是指定以这种方式工作的。我以为super大致等同于this.__proto__.__proto__,因此super.__proto__应该等同于this.__proto__.__proto__.__proto__表现出我期望的行为。您知道规范中在哪里super指定了确切的行为吗?
詹斯·摩瑟

@JensMoser:我会找到它的,但是可以想象正常使用super,例如super.setFoo('bar')。您不希望在原型而不是实例上进行操作。
Ry-

@georg我知道这__proto__是的访问器属性Object.prototype。当我要求参考规范时,我的意思是super结合一起参考了关键字的确切行为__proto__。看到我以前的评论。
詹斯·摩瑟

@ Ry-是的,我简化了一点。我的确切理解super.setFoo('bar')是,它等同于this.__proto__.__proto__.setFoo.call(this, 'bar')。因此,super自动使用正确的调用函数this
詹斯·摩瑟

1
@JensMoser super.__proto__(在Level3该类的方法中)完全等同于Reflect.get(Object.getPrototypeOf(Level3.prototype), "__proto__", this)
Bergi,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.