プロトタイプを使った多重継承とオーバライド - JavaScriptの個人的なメモ

今回は、多重継承を、JavaScriptのプロトタイプの機能を使いながら実現していきたいと思います。
二つの擬似クラスとして、SuperClass1とSuperClass2を作っておいて、それを、Childクラスに継承させるというやり方です。

  Function.prototype.create = function () {
    this.prototype = arguments[0] || {constructor:this};
    return new this();
  };

  var SuperClass1 = function () {
        this.hoge = function () {
          return 12;
        };
      },

      SuperClass2 = function () {
        this.hoge = function (n) {
          return n+1;
        };
        this.p = function () {
          return "Hello, World!";
        };
      },

      Child = function () {
        var super1 = SuperClass1.create(this),
            super2 = SuperClass2.create(super1),
            t = Object.create(super2);

        t.hoge = function () {
          return 15;
        };

        t.add = function() {
          var s = super1.hoge() + super2.hoge(1) + this.hoge();
          return s;
        };
        return t;
      },

      s1 = SuperClass1.create(),
      s2 = SuperClass2.create(),
      c = Child.create();

s1.hoge();  // 12
s2.hoge(1); // 2
c.hoge();   // 15

c.add();    // 29

Childクラスから作ったオブジェクト c は addメソッドを持っています。また、hogeメソッドをオーバライドしています。
さらに、SuperClass2クラスから継承したpメソッドも使えるのでやってみましょう。

c.p();    // Hello, World!

instanceof

JavaScriptには、型チェックのために、instanceofというものがありますが、これも使えます。

(c instanceof SuperClass1); // true
(c instanceof SuperClass2); // true
(c instanceof Child);       // true

(c instanceof Array);       // false

constructor

constructorは以下の例を見ればわかりますように、コンストラクタ関数が必ずしも一致しないという課題を抱えています。
たとえば、プロトタイプを使った一般的な継承を見てみましょう。

 var F = function(){},
     G = function(){};
G.prototype = new F();

var f = new F(),
    g = new G();
(f.constructor === F); // true
(g.constructor === G); // false

しかし、上記の方法を使いますと、この課題を解決します。

 var F = function() {},
     G = function() {
           return F.create(this);
         };

var g = G.create();
(g.constructor === G); // true

オブジェクトgのコンストラクタは、呼び出し時には、いつもcreateメソッドに引数を渡さない限り、Gクラスを格納するようになります。

createメソッドの使い方

createメソッドは次のような使い方をします。

 var F = function() {
       /*メソッドの定義*/
       this.hoge = function(){
         return 12;
       };
     },
     f = F.create();

f.hoge(); //12

続けて、createメソッドに引数を渡してみましょう。ここでは、propプロパティが12となるオブジェクトを作っておいて、引数として渡します。

 var F = function() {
       /*メソッドの定義*/
       this.hoge = function(){
         return this.prop;
       };
     },
     f = F.create({
         prop: 12
       });

f.hoge(); //12

オブジェクト f は prop プロパティを呼び出すことができます。
引数はどのような型のオブジェクトでも問題ありません。配列でも、正規表現でも、好きなオブジェクトを引数に入れることができます。

追記 (2013年6月24日)

IE8では、newメソッドの名前を使えないので、代わりに、createメソッドを使うように改善しました。また、Object.createは、IE8用のコードを追加した方がよいかもしれません。