次の2つの継承がある。
-
- クラスベースの継承
- プロトタイプベースの継承
Javaを知っている人なら、クラスベースの継承に馴染みがあるはず。
Javaの場合
public class Super{ public void print1(){ System.out.println("super1"); } public void print2(){ System.out.println("super2"); } } public class Sub extends Super{ public void print2(){ System.out.println("sub2"); } } public class Main { public static void main(String[] args){ Super sup = new Super(); Sub sub = new Sub(); sup.print1(); // "super1"と標準出力 sub.print1(); // "super1"と標準出力 sup.print2(); // "super2"と標準出力 sub.print2(); // "sub2"と標準出力 } }
SubクラスはSuperクラスを継承しているので、Subクラスのオブジェクトに対してもprint1メソッドを呼び出せる。
また、SubクラスはSuperクラスのprint1メソッドをオーバーライドしているので、Subクラスのオブジェクトに対してprint2メソッドを呼び出すと、Superクラスのprint2メソッドではなく、Subクラスに定義したprint2が実行される。
JavaScriptの場合
次のようにすれば、SubクラスはSuperクラスのプロパティを継承できる。
// スーパークラスの定義 var Super = function(){ this.name = 'super'; this.showName = function(){ alert(this.name); }; } // サブクラスの定義(空っぽ) var Sub = function(){ } // SubクラスのprototypeプロパティにSuperクラスのインスタンスを設定する Sub.prototype = new Super();
Superクラスのプロパティを継承していることを確かめる。
// Subクラスのプロパティには直接何も設定していないがSuperクラスのメソッドを呼び出せる。 var sub = new Sub(); sub.showName(); // "super"と表示
継承しているので、instanceof演算子の評価結果はSuperに対しても「true」となる。もちろんObjectクラスはすべてのクラスが継承しているのでObjectに対しても「true」となる。
// 勿論、すべてtrue alert(sub instanceof Object); // "true" alert(sub instanceof Super); // "true" alert(sub instanceof Sub); // "true"
subに対してshowName()メソッドを呼び出せるからといって、subがshowName()メソッドを直接所有している訳ではない。プロトタイプオブジェクトをいじれば挙動が変わる。
Sub.prototype.name='super(chenged)'; sub.showName(); // "super(chenged)"と表示
それはhasOwnPropertyメソッドでも確かめられる。
alert(sub.hasOwnProperty('name')); // "false"と表示
つまり、sub.showName()メソッドが呼ばれてはいるが、sub.prototype.showName()メソッドが実行されている。
だからこそ、変数subが参照するオブジェクトに同名のプロパティを設定して、継承プロパティをオーバーライドすることができる。
sub.name='sub'; sub.showName(); // "sub"と表示される。
hasOwnProperty()メソッドでも、オーバーライドしていることがわかる。
alert(sub.hasOwnProperty('name')); // "true"と表示
ということは、独自プロパティを削除すれば、元に戻る。「undefined」になることはない。
// Subクラスに直接設定したプロパティを削除すれば元に戻る。 delete sub.name; sub.showName(); // "super(changed)"と表示
まとめ
-
- JavaScriptはプロトタイプベースの継承をサポートしている。
- コンストラクタ関数.prototypeプロパティに設定したオブジェクトを継承できる。
- 継承先にプロパティをコピーするのではなく、継承先がそのプロパティを所有しているように見せかけるだけ。
- プロトタイプのプロパティ値を変更すると、それを継承しているオブジェクトは影響を受ける。