継承を理解する

継承は共通の振舞いを親に置き、必要な差だけを派生側へ加える仕組みです。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のたびに別配列ができます。継承された初期化の処理は共通でも、初期化される実体の状態まで常に共有されるわけではありません。

図解

二つの継承経路
staticの経路と、実体から通常メソッドを探す経路を混ぜない。

重要ポイント

  • extendsは実体側とクラス側の二つの継承経路を作る。
  • 派生constructorのthisはsuper後に使う。
  • superの探索先とthisの実体は別に考える。
  • 親constructorも生成する実体ごとに実行される。

間違えやすい点

  • 親メソッドが上書き後も自動実行されると思わない。
  • staticが派生実体にもコピーされると思わない。
  • superを通常メソッド呼出しのように何度も使わない。

用語解説

派生class
extendsによって別のclassを基に定義したclass。
オーバーライド
派生側に同名メソッドを定義し、通常の探索でそちらを優先させること。
super
派生constructorでの親の構築、又はメソッド内での親側プロパティ探索を表す構文。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。