• ベストアンサー

Array.prototype は使用しない方がいい?

prototypeの有名な問題にobjentオブジェクト汚染、Arrayオブジェクト汚染があると思います。 - 現在ブラウザに実装されているJavaScriptにはforEachがない - forEachの代替としてfor~inが使われている - for~in はオブジェクトのプロパティを列挙する - forEachの代替としてfor~inが使われる事を考慮して、object.prototype は使用すべきではない Object オブジェクトの prototype に便利メソッドを放り込むのはやめて頂きたい - nazonoDiary http://d.hatena.ne.jp/nazoking/20050425/1114374966 for...in - MDC https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Statements/for...in この理屈はわかります。 一方、Array.prototype はなぜ使用してはいけないのでしょうか? ---- // 数値添字配列 Array.prototype.test=function(){ return 'test'; }; var arr = [1,3,5,7,9]; for(var i=0,l=arr.length; i<l; i++){ console.info(arr[i]); // コンソール出力(要Firebug) } // オブジェクト (連想配列ではない) Array.prototype.test=function(){ return 'test'; }; var arr = { a:1,b:3,c:5,d:7,e:9 }; for(var i in test){ console.info(test[i]); // コンソール出力(要Firebug) } ---- どちらも問題なく動作します。 問題が発生するとすれば「数値添字配列でfor~inを使用するケース」ですが、それは実装が誤っていると思います。 for~inはオブジェクトのプロパティを列挙する仕組みなので、prototypeで拡張したプロパティまで列挙されるのは自然な動作です。 私はこれを「for~inバグ」と呼ばれることに違和感を覚えるのですが…。 「数値添字配列でfor~inを使用するライブラリがとても多いから、Array.prototype は止めよう」ということなのでしょうか? JavaScript の Array オブジェクトを汚染させずに拡張してみる - Cyokodog::Diary http://d.hatena.ne.jp/cyokodog/20081031/ArrayExtend01

質問者が選んだベストアンサー

  • ベストアンサー
  • KI401
  • ベストアンサー率53% (44/82)
回答No.1

> 一方、Array.prototype はなぜ使用してはいけないのでしょうか? 別に法律で規制されてるわけでもなし、使用しては「いけない」ことはないと思う。 単に、普通ならこんな汚染ライブラリ使いたくないよね?ってだけのハナシ。 じゃ「使いたくない」って、それはなぜか? 保守性が悪くなるからだ。 バグの原因になるからだ。 例えば最近ここで回答したんだけど:  http://okwave.jp/qa5024378.html prototype.jsを使わないコードでは問題ないのに、prototype.jsを使っただけで動作が一気に変になる。 これが良いことか悪いことかと言えば、普通の感覚で申し上げればそりゃ「悪い」ことだ。 例えばあなたが書いたJavaScriptのコードがあって、職場で他の人が そのページにprototype.jsを使って別な機能を追加したとする。 今まで動いていたあなたのコードは、たったそれだけの理由でおじゃんになるかもしれない。 よもやライブラリが原因だろうなんて思わないから、あなたも同僚も なぜそうなるのか原因が分からなくて途方にくれるかもしれない。 > 問題が発生するとすれば「数値添字配列でfor~inを使用するケース」ですが、それは実装が誤っていると思います。 その通りだと思う。もともと配列でfor-in文は使用すべきではない。 配列が疎であることが分かっている場合に限って使えばいい。 普通、配列が疎になることはあまりないから、for文で事足りる。 …が、ライブラリでは、配列一般に対応させたいからfor-in文を使っていることが多い。 この場合でも、object#hasOwnPropertyメソッドを使うことで汚染の影響は回避できる。 # hasOwnProperty()の知名度はもっと上がるべきだ。 どっちにしても、実装を間違えなければ問題は起こらない。 だから、そういうところまで把握した上で、「俺はベテランだからそんなミスは犯さないぜ!」 と言ってライブラリを利用するならば、それは問題ないのではないかと思う。  「初心者だから分かりません!これこれこうこうするにはどうすればいいですか?」  「prototype.jsを使えば簡単にできますよ^^」 とかいう流れに対してprototypeを初心者に勧めるんじゃねーよとか思って  「prototype.jsはfor~inバグを引き起こすので使ってはいけない。」 と発言するわけであって、一般にオススメできるようなものではないという文脈でよく「禁止」するかな。 さっきも言ったが、暴れ馬を制御できるってんならいいぜ?だがやはり初心者には暴れない馬を勧めたいね。 > for~inはオブジェクトのプロパティを列挙する仕組みなので、prototypeで拡張したプロパティまで列挙されるのは自然な動作です。 > 私はこれを「for~inバグ」と呼ばれることに違和感を覚えるのですが…。 これもその通り。 さっきも書いたが、for-in文はhasOwnProperty()を伴って書くべきものだ。 そうすればprototypeのメンバがループに回ってくることはない。 バグが起こるとすればhasOwnProperty()を伴わないfor-in文だが、これは実装が悪いだけ。 でもそういう実装が多くて、そういう不具合が多いために、俗に"for-inバグ"と呼ばれるんだろうね。 # ちなみに配列はlengthプロパティ持ってるけどね。for-in文では列挙されない仕様だ。 > どちらも問題なく動作します。 # あと、どうでもいいが・・・ # × for(var i in test) → ○ for(var i in arr) だよね

think49
質問者

お礼

詳しい説明ありがとうございます。 > よもやライブラリが原因だろうなんて思わないから、あなたも同僚も > なぜそうなるのか原因が分からなくて途方にくれるかもしれない。 他の人への配慮のためでもあるのですね。「初心者には暴れない馬を勧めたい」の理由がよくわかります。 > …が、ライブラリでは、配列一般に対応させたいからfor-in文を使っていることが多い。 ライブラリではfor-in文が採用されることが多いのですね。 > # hasOwnProperty()の知名度はもっと上がるべきだ。 hasOwnProperty() メソッドの存在は知りませんでしたので、試しに使用してみました。 hasOwnProperty - MDC https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Global_Objects/Object/hasOwnProperty ---- // 数値添字配列 Array.prototype.test=function(){ return 'test'; }; var arr = [1,3,5,7,9]; for(var key in arr){ if(arr.hasOwnProperty(key)){ console.info(arr[key]); // コンソール出力(要Firebug) } } // オブジェクト Object.prototype.test = function(){ return 'test'; }; var arr = { a:1,b:3,c:5,d:7,e:9 }; for(var key in arr){ if(arr.hasOwnProperty(key)){ console.info(arr[key]); // コンソール出力(要Firebug) } } ---- 素晴らしい。実装を整えれば、どんなオブジェクトをprototypeで拡張されても対応できますね! > # × for(var i in test) → ○ for(var i in arr) だよね ご指摘ありがとうございます。 初めは "test" を変数名にしてましたが、思い直して変数名を変更したときに修正しそびれたようです。 おかげさまでArrayオブジェクト汚染について詳しく知ることが出来ました。 特に、hasOwnProperty() メソッドの存在には驚かされました。こんな便利なメソッドがあるとは! これからはprototypeにも注意を払ってコーディングしていきます。 ありがとうございました。

その他の回答 (1)

回答No.2

ごめん!まったくかんけいない、ぜんかいのしつもんのことだけど IEでも、だい1ひきすうには、いべんとが・・・ <div id="a">Event List</div> <script type="text/javascript"> (function (event_info) {  if (window.addEventListener) {   document.addEventListener ('click', event_info, false);  } else if (window.attachEvent) {   document.attachEvent('onclick', event_info);  } })(  function (e) {   var str = '第1引数は、eventの・・<br>';   var key;   for (key in e) {    str += 'event.' + key +' = ' + e[key] + '<br>';   }   document.getElementById('a').innerHTML = str;  } ); </script>

think49
質問者

お礼

お礼が遅くなりました。m(_ _)m いろいろと情報を求めて遅くなってしまいました。 > ぜんかいのしつもんのことだけど 下記質問ですね。気にかけていただいてありがとうございます。 イベントリスナに登録される function(e){} の "e" はeventオブジェクト? -OKWave http://okwave.jp/qa5075946.html > IEでも、だい1ひきすうには、いべんとが・・・ おお、IEでも第一引数にイベントオブジェクトを渡せるのですか。 これはすっきりしますね! この件に関して公式な文献(MSDN)を探しましたが、どうしても見つけることができませんでした。 下記URLは window.event を使う方法。(windowを省略してます) attachEvent Method (A, ABBR, ACRONYM, ...) http://msdn.microsoft.com/en-us/library/ms536343%28VS.85%29.aspx 「Tag index」にeventオブジェクトを渡すコードが載っていました。 掲示板/JavaScript質問板/過去ログ/一覧/ addListener()やattachEvent()で引数 - TAG index Webサイト http://www.tagindex.com/kakolog/q4bbs/901/1162.html この件に関して紹介しているサイトが非常に少ないようです。 私もbabu_babooさんに教えていただけなければ、上記BBSを見つけることはできなかったと思います。 もっと認識されるべき方法だと思うのですが、残念です。 # IEがaddEventListenerに対応してくれればいうことはないのですが、なぜいつまでもattachEventを引きずるのか…。 ありがとうございました。

関連するQ&A

専門家に質問してみよう