この方法ではArrayを継承することは… できないッ!
「まるごとJavaScript & Ajax ! Vol.1」買いました。
- 作者: 天野仁史,舘野祐一,川崎有亮,arton,田中孝太郎,国分裕,山本有悟,海野裕也,nanto_vi
- 出版社/メーカー: インプレス
- 発売日: 2007/02/15
- メディア: 大型本
- 購入: 8人 クリック: 98回
- この商品を含むブログ (78件) を見る
えーと、最初にartonさんのJavaScriptの落とし穴があって、その次が弾さんプロタイプベースオブジェクト指向の解説(404 Blog Not Found:javascript - プロトタイプ的継承とか)があって、その次がid:amachangのPrototype.jsの解説で、その先が…でとにかく盛りだくさんですね!
あっ。
弾さん、それまずい。
前から気づいてたんですけど、その方法じゃArrayを継承することはできないです。
継承されたArrayがうまく動かない例
function myArray(o) { function F() {} F.prototype = o; return new F(); } var proto = [0, 1, 2]; var myary = myArray(proto); alert(myary.length + ' : ' + myary.join(',')); myary.push(3); alert(myary.length + ' : ' + myary.join(',')); // IEでは追加した要素が表示されない。 myary[4] = 4; alert(myary.length + ' : ' + myary.join(',')); // IE, Firefoxともに追加した要素が表示されない。 alert(myary.pop()); // IEでは2, Firefoxでは3が表示される。
Firefoxでも、IEでも期待通りに動いてはくれません。
myaryはブラケット([ ])で要素を追加したときにlengthが更新されないようです。
じゃあ、どうやってArrayを継承すればいいの?うーむ…わかりません。
追記(2/22)
id:delive1さんがブクマコメントで、
Arrayとかの組込みObjectはvalueOf、toStringをイジるのだけでいいかと
http://b.hatena.ne.jp/dlive1/20070222#bookmark-4029980
とおっしゃられている。「JavaScript継承パターンまとめ - Thousand Years」のリンクを書いてくれたid:trickstar_osさんも同じことを言いたいのだと思います。
しかし、その方法でうまくいくのはStringやNumberの各メソッドが内部的にtoStringやvalueOfを呼び出しているからです。Arrayの場合はそれに該当するような根幹的なメソッド*1は存在しないのでこの方法は、残念ながらまったく解決になりません。
問題の本質は rubyでいうところの []= をユーザが定義できないことです。これを解決するにはjavascript2.0を待つ以外には方法は無いのでは無いかと思います。
自分が試した中で一番まともに動いたのはこんな感じです。
// Firefox Only function MyArray(strage) { strage = Array.apply(null, strage) || []; this.__noSuchMethod__ = function(name, args) { strage[name].apply(strage, args); } this.toString = function() {return strage.toString();} this.__defineGetter__("length" , function() {return strage.length;}); this.__defineSetter__("length" , function(l) {return strage.length =l;}); this.get = function(i) { return strage[i]; }; this.set = function(i, v) { return strage[i] = v; }; } ary = new MyArray([1,2,3]); alert(ary.length + ' : ' + ary); ary.push(4); alert(ary.length + ' : ' + ary); ary.set(0, 0); alert(ary.length + ' : ' + ary); ary.set(10, 10); alert(ary.length + ' : ' + ary);
Firefoxオンリーですがポイントは以下の通り
- []を使うのをあきらめてgetとsetを使う(javaみたいだ)
- __noSuchMethod__でメソッド呼び出しをArrayに委譲する(継承じゃ無いじゃん)
- __defineGetter__と__defineSetterでlengthの読み書きをArrayに委譲する
実際のところは、「Arrayをどーしても継承したい」なんて人はいないと思うので全然問題ないのですが。