
ワタル
先日親クラスの状況を調べようと思って
super.__proto__
を使ったら結果が意味不明だったので報告です。

アキラ
superって親クラスのメソッド呼ぶときに使うやつだよね。

ワタル
それ。でも、親クラスって言っても、superが使われているクラスの親なのか、実行時のthisの親なのか知ってる?

アキラ
あれどっちだろ。

ワタル
やってみようか。
class Parent {
f() {
console.log('Parent.f();')
console.log(this);
}
}
class Child extends Parent {
f() {
super.f();
console.log('Child.f();');
console.log(this);
}
}
class Parent2 {
f() {
console.log('Parent2.f();')
console.log(this);
}
}
class Child2 extends Parent2 {
f() {
super.f();
console.log('Child2.f();');
console.log(this);
}
}
const c = new Child();
const c2 = new Child2();
const f = c.f.bind(c2);
f();
出力結果
Parent.f();
Child2 {}
Child.f();
Child2 {}

アキラ
thisがChild2のインスタンスで、super使って呼ばれてるのが
Parent.f()
だから、superが書かれているクラスの親のメソッドを呼んでるね。thisの親じゃなくって。

ワタル
そう。MDNのリファレンスにも↓のように書いてあるんだけど、残念ながら2023-01現在、日本語版のページにはその部分翻訳されてないのよね。
Note that the reference of super is determined by the class or object literal super was declared in, not the object the method is called on. Therefore, unbinding or re-binding a method doesn't change the reference of super in it (although they do change the reference of this).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super

ワタル
でも、挙動もドキュメントも一致してるから、めでたしめでたしかと思ったらそうはいかなかったのよ。

アキラ
?

ワタル
superの挙動いろいろやってみてもちゃんと上の通りでいいんだけど、なぜか
super.__proto__
だけは挙動が違う。
class GrandParent {
}
class Parent extends GrandParent{
f() {
console.log('Parent.f();')
console.log(this);
console.log(super.__proto__);
console.log(this.__proto__);
console.log(this.__proto__ === super.__proto__);
}
}
class Child extends Parent {
f() {
super.f();
console.log('Child.f();');
console.log(this);
console.log(super.__proto__);
console.log(this.__proto__);
console.log(this.__proto__ === super.__proto__);
}
}
class Parent2 {
f() {
console.log('Parent2.f();')
}
}
class Child2 extends Parent2 {
f() {
super.f();
console.log('Child2.f();');
}
}
const c = new Child();
const c2 = new Child2();
const f = c.f.bind(c2);
f();
出力結果
Parent.f();
Child2 {}
Parent2 {constructor: ƒ, f: ƒ}
Parent2 {constructor: ƒ, f: ƒ}
true
Child.f();
Child2 {}
Parent2 {constructor: ƒ, f: ƒ}
Parent2 {constructor: ƒ, f: ƒ}
true

アキラ
なにこれ。思いっきり
this
に引っ張られてるじゃん。

ワタル
そう。さらにどの階層かによらず単に
super.__proto__
は、this.__proto__
と同一のものをさしてるようなんだよね。

ワタル
最初chromeでやってみてこうだったので、なんじゃこりゃと思ってfirefoxでもやってみたけど同じ。

アキラ
MDNの説明と違うようだけどなにこれ?

アキラ
回答付いてるけど会話が噛み合ってないね。これ。

ワタル
書いてないけど、質問してる人はjsの仕様を自分でいろいろ探したけれど見つからないから質問投稿してるっぽいし、僕も少し探したけれどやっぱり見つけられなかった。

アキラ
変な挙動だと思うけど、変わる可能性あるのかなぁ?

アキラ
じゃ、この記事的には、
super.__proto__
は使わないほうがよさそうってことで。閉めましょうか。

ワタル
そだね。