継承を理解する
継承は共通の振舞いを親に置き、必要な差だけを派生側へ加える仕組みです。extendsが作る二つの参照関係と、superによる初期化・親メソッド呼出しを分けて学びます。
この単元で学ぶこと
- extendsの実体側とクラス側のチェーンを説明する
- 派生constructorのsuperとthisの順を守る
- 上書きと親メソッド呼出しを追跡する
本文解説
共通部分と差分 class A{read(){return "A";}} class B extends A{}ではnew B().read()がAを返します。Bにreadを書かなくてもA.prototypeのメソッドを探索できます。Bへ別のreadを定義すればそのメソッドが優先されます。継承は同じコードを自動実行する機能ではなく、探索関係を作って共通の振舞いを利用する機能です。
実体側の継承経路 new B()で作ったbの直接プロトタイプはB.prototype、その次がA.prototypeです。Object.getPrototypeOf(B.prototype)===A.prototypeはtrueです。b.readはb自身、B.prototype、A.prototypeの順に探します。bへ所有readを作れば、さらに手前で一致して親と子のメソッドを隠します。
親の初期化を利用する class A{constructor(n){this.n=n;}} class B extends A{}ならnew B(4).nは4です。派生constructorを省略すると既定constructorが引数を親の構築へ渡します。自分でconstructorを書くならconstructor(n){super(n);this.n++;}のように、親で基礎状態を作った後に追加の初期化を行います。この例では結果は5です。
superより先にthisを使わない 派生constructorではsuper(...)が親の構築を行い、この実体のthisを初期化します。その前にthis.n=1とするとReferenceErrorです。superを二回呼ぶことも同じthisの再初期化となり失敗します。通常の親classを継承し、派生constructorが自分のthisを使う例では、親の初期化を一回済ませてから使う順序を守ります。
同名メソッドを上書きする class B extends A{read(){return "B";}}ならb.read()はBです。親のreadを自動的に先に実行するわけではありません。親の戻り値も使いたいときはread(){return super.read()+"B";}と明示し、親がAを返せばABになります。this.read()を代わりに書くと同じ派生メソッドを再び呼び、再帰になる点にも注意します。
superで呼んでもthisは実体 親にread(){return this.n;}があり、派生実体のnを7にしたなら、super.read()も7を返します。superはメソッドをどこから探すかを変えますが、親専用の別オブジェクトを受け手にするわけではありません。親メソッドを探索する開始位置と、その中で使うthisの実体を分けて考えます。
staticの継承は別の経路 class A{static kind(){return "A";}} class B extends A{}ならB.kind()はAです。クラス側にもBからAへのプロトタイプ関係が作られます。ただしnew B().kindにはこのstaticは現れません。実体用のB.prototype→A.prototypeと、クラス側のB→Aの二本の矢印を別々に描きます。
instanceofと個別の状態 b instanceof Bとb instanceof Aは、通常のこの継承関係では両方trueです。プロトタイプチェーンに各constructorのprototypeがあるかを調べます。また親constructorでthis.items=[]とすれば、newのたびに別配列ができます。継承された初期化の処理は共通でも、初期化される実体の状態まで常に共有されるわけではありません。
図解
重要ポイント
- extendsは実体側とクラス側の二つの継承経路を作る。
- 派生constructorのthisはsuper後に使う。
- superの探索先とthisの実体は別に考える。
- 親constructorも生成する実体ごとに実行される。
間違えやすい点
- 親メソッドが上書き後も自動実行されると思わない。
- staticが派生実体にもコピーされると思わない。
- superを通常メソッド呼出しのように何度も使わない。
用語解説
- 派生class
- extendsによって別のclassを基に定義したclass。
- オーバーライド
- 派生側に同名メソッドを定義し、通常の探索でそちらを優先させること。
- super
- 派生constructorでの親の構築、又はメソッド内での親側プロパティ探索を表す構文。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
- https://html5exam.jp/outline/objectives_lv2.html
- https://tc39.es/ecma262/2024/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ordinarycallbindthis
- https://tc39.es/ecma262/2024/multipage/ecmascript-language-functions-and-classes.html#sec-class-definitions
- https://tc39.es/ecma262/2024/multipage/ecmascript-language-statements-and-declarations.html#sec-try-statement
確認問題の出題・採点や学習履歴の保存にはログインが必要です。