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;
...
}