JavaScriptでは他の言語と異なり、
正確には「クラス」というものは存在しません。あるのは「function」です。
しかし、この「function」はオブジェクト化することが出来ますので、
クラスの様に振る舞い、扱うことが出来ます。
JavaScriptの基本的なクラスとしての考え方は、下記を参照してください。
JavaScriptのクラス定義方法を徹底解説!!
そして、今回のテーマと同じように、継承関係にある親子クラスの取り扱いとして、
親クラスに対してパラメータ付きで初期化したい場合は下記の記事も参照してください。
[JavaScript]子クラスから親クラスを引数付きで初期化する方法
ただ、JavaScriptでのクラスは、正確には完璧なるクラスではありませんので、
ちょっとしたことで「どうやるんだっけ?」と、悩むことが多いかと思います。
今回は、JavaScriptでは単純に用意されていない機能を、自身で実装していきます。
テーマとして、子クラスから親クラスを参照し、親クラスの同名メソッドを呼び出す方法について解説します。
JavaScriptには親クラスを参照する「super」が無い
他のオブジェクト指向言語では「super」などの予約語を使用して親クラスを参照し、
親クラスのメソッドを起動することが出来ますが、
JavaScriptには、そのような機能はありません。
そこで弊害となるのが同名メソッドです。
JavaScriptでは、親クラスと異なる名前のメソッドの場合は、
そのまま自身を参照することで親クラスのメソッドも起動することが出来ますが、
子クラスと親クラスで同じ名前のメソッドが有った場合、子クラスにてオーバーライドされてしまうので、
通常では親クラスの同名メソッドを呼び出すことは出来ません。
スタティックメソッドとして呼び出すことは可能ですが、インスタンス内に設定したプロパティを
引き継ぐことが出来ません。
ですが、クラスを継承するというのは、親クラスに対して「拡張」したい場合がほとんどです。
拡張対象はプロパティやメソッドの他にも、親クラスのメソッド自体を拡張したい事があります。
具体的には、親クラスのメソッドの事前処理を追加したい場合に、子クラスのメソッド内にて事前処理を行った後に
親クラスのメソッドを起動します。
その際、メソッド名を分けてオーバーライドさせない様にするか?オーバーライドしつつ親クラスのメソッド処理を
コピペで持ってくるか?と考えてしまいますが、どちらもよろしくありません。
出来れば、同名メソッドにてオーバーライドし、かつ内部で親クラスのメソッドをインスタンスを保持しながら
起動出来ることが理想です。
続いて、上記のような子クラスのメソッド内から親クラスの同名メソッドを
インスタンスを保持した状態で起動する方法について解説します。
子クラスから親クラスの同名メソッドを呼び出す
子クラスから親クラスの同名メソッドを呼び出すには、
通常の「prototype」による継承に加え、親となるクラスの「prototype」をプロパティとして保持します。
サブクラス内から同名の親クラスメソッドを呼ぶ場合には、保持した親クラスの「prototype」を経由して起動します。
そうすることで、サブクラスのインスタンス情報を保持したまま親クラスのメソッドを呼ぶ事が出来ますので、
同じプロパティを参照することが出来ます。
具体的には、下記コードをご覧ください。
/* 親クラス ----------------------------------------------------*/ function SuperClass(){ } // 親クラスのメソッド SuperClass.prototype.testMethod = function(){ console.log( 'superClassLog=' + this.name ); } /* 子クラス ----------------------------------------------------*/ function SubClass(){ this.name = 'hamada'; this.super = SuperClass.prototype; } // 親クラスを継承 SubClass.prototype = new SuperClass(); // 子クラスのメソッド SubClass.prototype.testMethod = function(){ console.log( 'subClassLog=' + this.name ); // 親クラスの同メソッドを起動 this.super.testMethod.call( this ); } // 子クラスをインスタンス化してメソッドを起動する var subClass = new SubClass(); subClass.testMethod();
上記コードを実行すると、コンソール上には下記のように表示されます。
subClassLog=hamada
superClassLog=hamada
まず、子クラスをインスタンス化し、自身のメソッドを起動します。
すると、自身のコンストラクタ上で設定した値「hamada」と共に、
「console.log( 'subClassLog=' + this.name );」にてログが出力されます。
次に、「this.super.testMethod.call( this );」にて親クラスの同名メソッドを起動しますが、
予め保持しておいた親クラスの「prototype」を経由してメソッドを読んでいることがポイントです。
その際、インスタンスを継続させる為に、「call()」にてメソッドを起動しています。
「call()」は、メソッドを起動させることの出来るJavaScript標準の関数です。
第一引数には、呼び出し先のメソッド内で使用される「this」の値を設定することができ、
第二引数以降はメソッドに渡したい引数を指定します。
今回の例では、第一引数に「this」を指定していますので、
呼び出し先である親クラスのメソッド内で「this」を使用すると、子クラスのインスタンスが参照出来るようになります。
もちろん、継承していれば親クラスのプロパティも子クラスのインスタンスから参照出来ますので、
通常通り「this」の値を扱うことが出来ます。
ですので、親クラス内で「console.log( 'superClassLog=' + this.name );」としても、
子クラスのコンストラクタ内で設定された値を参照することができ、
コンソール上に「superClassLog=hamada」と表示させることが出来ます。
これで、子クラスのメソッド内からインスタンス情報を保持したまま
親クラスの同名メソッドを起動出来る様になりました。
JavaScriptは、とても柔軟で扱いやすいですが、他の言語に比べ用意されていないものが多いですので、
必要に応じて自分で自作する必要があります。
JavaScriptでは、こういった手法を知っている人と知っていない人では、
コード設計がまったく異なってしまいますので、なるべく知識を共有出来ればと思います。
今回紹介した方法以外にも、同じことが出来る方法がありましたら
コメントにて教えて頂ければ幸いです。
何卒、よろしくお願い致します。