JavaScriptで(super .__ proto__ === this .__ proto__)がtrueなのはなぜですか?


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()を呼び出すことを期待してLevel1いましたsuper.__proto__ !== this.__proto__。代わりに、super.__proto__.myFunc();実際myFunc()にclassを呼び出しLevel3(それ自体を呼び出し)、2番目の呼び出し時myFunc()にclassを呼び出しますLevel2。これはsuper.__proto__ === this.__proto__、コードが示すように完全に理解可能です。

super.__proto__ === this.__proto__この例で理由を説明できますか?可能であれば、仕様の関連セクションへの参照も提供してください。

回答:


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指定されているか知っていますか?
Jens Moser、

@JensMoser:少しわかりますがsuper、などの通常の使用を想像してみてくださいsuper.setFoo('bar')。インスタンスの代わりにプロトタイプを操作したくないでしょう。
Ry-

@georgはの__proto__アクセサプロパティObject.prototypeです。仕様への参照を求めたときsuper、と組み合わせたキーワードの正確な動作への参照を意味していました__proto__。以前のコメントを参照してください。
Jens Moser、

@ Ry-はい、少し簡略化しました。私の正確な理解はsuper.setFoo('bar')、と同等であることthis.__proto__.__proto__.setFoo.call(this, 'bar')です。したがって、super適切なで関数を自動的に呼び出しますthis
Jens Moser、

1
@JensMoser super.__proto__Level3クラスのそのメソッド内)は次とまったく同じですReflect.get(Object.getPrototypeOf(Level3.prototype), "__proto__", this)
Bergi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.