2006年10月18日 21:00 [Edit]

javascript - プロトタイプ的継承完全版

Kazuho@Cybozuさま、いつもありがとうございます。

Kazuho@Cybozu Labs: JavaScript の String 型を継承する
 結論から言うと、String 型も継承っぽいことができます。こんな感じ。

おかげでプロトタイプ的継承モデルの完全版が出来ました。


AtomicなObjectを継承

これは、以下のように包括的に出来ます。

var Atomic = function(C){
    var P = function(v){ this._v = v; };
    P.prototype = new C;
    P.prototype.valueOf  = function(){ return this._v.valueOf(); }
    P.prototype.toString = function(){ return this._v.toString(); }
    return P;
}

使うときはこんな。

var MyStr = Atomic(Str);
MyStr.prototype.x = function(n){
  var str = '';
  while (n--) str += this;
  return new MyStr(str);
};
var mystr = new MyStr("foobar");

しかし、このままではAtomicな場合とそうでない場合を分けなければなりません。

object()の拡張

そこで、object()を以下のように拡張します。

var object = function(obj, base) {
    var P;
    switch ( typeof(obj) ) {
    case "boolean":
    case "number":
    case "string":
        P = Atomic((base || obj).constructor);
        break;
    // case "array": typedof([]) is "object".
    case "object":
        P = function(){};
        P.prototype = (base || obj);
        break;
    default:
        return;
    };
    P.prototype.method = function(o, f){
        if (typeof(o) == "string"){
            P.prototype[o] = f;
        }else{
            for (var p in o){
                P.prototype[p] = o[p];
            }
        }
    }
    return new P(obj);
}

これで、どんなObjectに対しても、obj.method()を使ってメソッドを追加できます。

var mystr = object("foobar");
mystr.method('x', function(n){
  var str = '';
  while (n--) str += this;
  return new MyStr(str);
});

しかし、このままではSingleton Methodの追加しか出来ないことになります。やはり大々的に使うには

var MyStr = function(o){
  // constructor を定義
}
var mystr = new MyStr("foobar");
var double = mystr.x(2);

のようにしたいところです。

Fake Constructorの定義

このMyStr()の定義をどうすればよいでしょうか?こうすればよいのです。

var MyStr = function(o){
    var self = object(o);
    self.method({
        'x': function(n){
            var str = '';
            while (n--) str += this;
            return new MyStr(str);
        },
        /* 他のmethodもここで定義 */
    });
    return self;    
}

ここで注目して頂きたいのは、MyStr()thisにはノータッチなことです。だからMyStr.prototype.x = function(){ /*... */ }は出来ません。しかし、その役割はself.method()が担っています。

あとは、

var mystr = new MyStr("foobar"); // 実はnewはあってもなくてもよい。
var double = mystr.x(2);

とすればいいわけです。

デモ

まとめると、こんな感じになります。

Boolean

Number

String

Array

Object

なんか足にささってなかなか抜けなかった刺が抜けた気分です。

Enjoy!

Dan the Prototyper


この記事へのトラックバックURL

この記事へのトラックバック
404 Blog Not Found:javascript - プロトタイプ的継承完全版
404 Blog Not Found:javascript - プロトタイプ的継承完全版【】at 2012年01月23日 02:30
Perl5の欠点:Object Systemが後付けなこと。 Perl5の利点:Object Systemが跡づけなこと。
perl - Object::PrototypeでPOMを実装【404 Blog Not Found】at 2006年10月22日 22:23
メモ http://blog.livedoor.jp/dankogai/archives/50662606.html
JavaScript【Miscellaneous】at 2006年10月19日 13:06
「404 Blog Not Found:javascript - プロトタイプ的継承」とその続編「404 Blog Not Found:javascript - プロトタイプ的継承完全版」は、案の定反応すべきbloggersが然るべき反応をしてくれた。これをbloggingの魅力と言わずしてなんと呼ぼうか。 プリミティブ値でもプ....
javascript - Prototypal Object Modelの落とし穴【404 Blog Not Found】at 2006年10月19日 11:39
最近、プロトタイプ的継承の話しが盛り上がっています。 http://blog.livedoor.jp/dankogai/archives/50662064.html http://labs.cybozu.co.jp/blog/kazuho/archives/2006/10/javascript_string.php http://blog.livedoor.jp/dankogai/archives/50662606.html 最終形がやた
[javascript] 関数一発でプロトタイプチェーンに繋げて、オブジェクトをクローンする。【IT戦記】at 2006年10月19日 05:31