Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why in JavaScript is (super.__proto__ === this.__proto__) true?

It seems that in JavaScript (ES6) Classes super.__proto__ === this.__proto__.

Can you explain why this is the case? The behaviour seems consistent across different browsers, so I suspect this is specified somewhere in the spec.

Consider the following code:

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();

I would have expected that super.__proto__.myFunc(); would call the function myFunc() of class Level1 and that super.__proto__ !== this.__proto__. Instead super.__proto__.myFunc(); actually calls myFunc() of class Level3 (it calls itself) and then on the second invocation it calls myFunc() of class Level2. This is perfectly comprehensible if super.__proto__ === this.__proto__ which the code demonstrates.

Can you explain the reason why super.__proto__ === this.__proto__ in this example? If possible, please also provide references to the relevant section of the spec.

like image 633
Jens Moser Avatar asked Oct 11 '19 21:10

Jens Moser


1 Answers

Object.prototype.__proto__ is a property with a getter[1]. It operates on its this value. There is no actual super object to be a this value (you couldn’t write Object.getPrototypeOf(super)), just a super way of looking up properties, so this.__proto__ and super.__proto__ mean the same thing as long as __proto__ isn’t also defined anywhere lower on the prototype chain.

Compare:

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__'));
like image 114
Ry- Avatar answered Oct 13 '22 01:10

Ry-