Arrayの継承、実はモダンブラウザ(ie7を除く)だと、ほぼ旨くいくんですね。
function extend(s, c) { function f() {}; f.prototype = s.prototype; //sはインスタンスでは無く、型でなければだめ c.prototype = new f(); c.prototype.__super = s.prototype; //オーバーライド用に保持 c.prototype.constructor = c; ... } Collection = extend(Array, function() { if (arguments.length == 1 && typeof n == "number") { return; } for (var i = 0; i < arguments.length; i++) { this.push(arguments[i]); } Collection.prototype.join = function(separator) { //オーバーライド return this.__super.join.apply(this, arguments); } }); foo = new Collection (1,2,3); foo.push(4); foo.push(5);
実際の実行結果は以下のとおり
本文の最初で「ほぼ」旨くいくとお茶を濁している原因がコンストラクターの部分でプリミティブなオブジェクトの
コンストラクターを継承先から呼び出しても期待通りの振る舞いをしてくれません。自作のクラスを継承した場合は
this.__super.constructor.aply(this, arguments);
とすれば旨くいくのですが・・・
そこで今回は強引に渡された引数を自前でpush
しています。
それからもう一つ、直接要素を指定した場合にlength
が正しく反映されません。
var c = new Collection(1,2,3);
c[3] = 4;
alert(c.length); //期待値は4
最後にie7でも上記2点以外を対応される方法(力業)を示します。
function extend(s, c) { function f() {}; if (s == Array) { var a = new s; f.prototype.constrctor = s; f.prototype.concat = a.concat; f.prototype.join = a.join; f.prototype.length = a.concat; f.prototype.pop = a.pop; f.prototype.push = a.push; f.prototype.reverse = a.reverse; f.prototype.shift = a.shift; f.prototype.slice = a.slice; f.prototype.sort = a.sort; f.prototype.splice = a.splice; f.prototype.unshift = a.unshift; } else { f.prototype = s.prototype; } c.prototype = new f(); c.prototype.__super = s.prototype; //オーバーライド用に保持 c.prototype.constructor = c; ... }