Javascript Arrayの継承

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

M. K. の紹介

IT屋さんです。プログラミングが大好きで今はJavascriptがお気に入りです。
カテゴリー: JavaScript, tips   タグ: ,   この投稿のパーマリンク