• ベストアンサー

removeEventListenerについて

JavaScript勉強中なのですが、removeEventListener("mousemove",funcname,!1)というメソッドの使い方というか、使い所がイマイチピンとこなくてこまっています。 addEventListener("mousemove",funcname,!1)で登録したイベントリスナーを削除するということだと思うのですが、削除した場合としなかった場合の違いって具体的にどういったことなんでしょうか? メモリリークとかの問題なのでしょうか? また、具体的に使う場合の簡単な例を教えてもらえないでしょうか? よろしくお願いいたします。

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

  • ベストアンサー
回答No.2

主な理由はメモリリーク対策だと思いますが、それ以外にもあります。 window.onloadのようにページ読み込みに1度だけ実行するようなものであれば、 「ハンドラを監視するためのメモリ」を解放することで 厳密にはリークしているわけではありませんが、全体の消費メモリの削減になります。 また、オブジェクトがドキュメントから削除される場合。(これがメモリリークの主な原因です。) <div id="div1"></div> <button id="btn1"></div> document.getElementById('div1').addEventListener('click', func, false); document.getElementById('btn1').addEventListener('click', function(){ div1=document.getElementById('div1'); div1.parentNode.removeChild(div1); } , false); このような場合では、div1が削除されたあとは、div1に登録されたclickイベントハンドラだけが使用できないまま残ることになります。 この場合も、removeEventListenerでイベントハンドラを削除しておいた方が、余分なメモリを使わなくて済みます。 document.getElementById('div1').addEventListener('click', func, false); document.getElementById('btn1').addEventListener('click', function(){ div1=document.getElementById('div1'); div1.removeEventListener('click', func, false); //メモリリーク対策 div1.parentNode.removeChild(div1); } , false); もう一つの例。 上の例ではdiv1を削除してから、もう一度btn1を押すと、「div1がない」というエラーになります。 そのため、div1の存在チェックをしてもいいのですが、 function(){ div1=document.getElementById('div1'); if(div1){  div1.parentNode.removeChild(div1); } } ボタンを押したときのイベントハンドラを削除し、何も起こらないようにすることもできます。 document.getElementById('btn1').addEventListener('click', function(event){ div1=document.getElementById('div1'); div1.removeEventListener('click', func, false); //メモリリーク対策 div1.parentNode.removeChild(div1); this.removeEventListener(event.type, arguments.callee, false); //連続クリック防止 } , false); *IE対策として、event.typeではなく'click'で処理する方が良いと思います。 *ボタンの場合はbtn1.disabled=trueという方法もあります。連続クリック防止はこの方法がよく使われます。 あと、!1というのはfalseのショートコーディングだと思います。

その他の回答 (5)

  • think49
  • ベストアンサー率59% (285/482)
回答No.6

#5 です。 重大なミスをしていることに気がつきました。 IE6 SP2- は addEventListener を持たないため、addEventListener で前述のメモリリークパターンにはなりません。 というわけで、サンプルを attachEvent に変更しました。 http://jsfiddle.net/fXHDk/1/ addEventListener でメモリリークパターンが存在するなら、addEventListener を使用可能なブラウザにメモリリークのバグが混入していることになりますね。 候補は IE9, Firefox, Google Chrome, Safari, Opera になるでしょうか。

  • think49
  • ベストアンサー率59% (285/482)
回答No.5

メモリリークとはブラウザに存在するバグの一種です。本来解放されるべきメモリが解放されない状態をメモリリークといいます。 ブラウザに存在するバグなので「特定のブラウザ」で「特定の状況」にならないとメモリリークは発生しません。 有名どころとして IE6 SP2- に存在した循環参照によるメモリリークパターンがあります。(Windows XP SP3 で修正済み) http://msdn.microsoft.com/ja-jp/library/bb250448%28v=vs.85%29.aspx 典型的なメモリリークパターンのサンプルを http://jsfiddle.net/fXHDk/ に置きました。 私の見たところでは #2 の方のコードはこのパターンではないようです。 他のメモリリークパターンも勿論あると思いますが、どのブラウザでどういう状況で発生するメモリリークなのか、を説明しないと質問者さんにも伝わらないのではないかなと思います。 # 私は「循環参照はバグが混入しやすい部分なので、可能な限り循環参照しないパターンにする方がよい」とアドバイスを受けたことがあります。 # おそらく、babu_baboo さんも同じような考えを持っているのだと思います。(違ったらすみません) --- addEventListener でイベントを定義するとブラウザは定義した回数だけメモリを消費します。 これは仕様通りの動作なのでメモリリーク(バグ)ではありません。 #2 でも指摘されていますが、一回だけ使用する window.onload など既に不要となったイベントがあれば removeEventListener で削除しておくのは良い習慣です。 不要になったイベントを削除することで低スペックなPCでも十分なパフォーマンスで動作することが出来るようになります。 また、window.onunload 時に全てのイベントを削除しておくことも良い習慣だといわれます。 (この習慣によって循環参照によるメモリリークを完全に防ぐことが出来ます。) --- > addEventListener("mousemove",funcname,!1) DOM4 では addEventListener の第三引数を指定しなかったときに false が適用される仕様を策定中です。 http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-eventtarget まだ Working Draft なので DOM4 に準じた書き方にするのはどうかと思いますが、念のため。 !1 はショートコーディングだと思いますが、false と比較して遅くなる点を指摘しておきます。 誤解されがちですが、「ショートコーディング === 高速」ではありません。 高速化するためにコードが長くなることはよくあります。

回答No.4

循環参照だけがメモリリークの原因ではないですよ。

回答No.3

メモリーリークもんだいは、「循環参照」がおこるからであって・・・

回答No.1

とうろくするものあれば、さくじょするのもあり・・・ ひつようが なくなったら はずすべき。(ふだんの かいとうでは めったに だれも かきませんね) でも、すぐに また つかうのなら それは、つかいかたが おかしい。 「れい」に、なってない?! function handler (event) {  switch (event.type) {  case 'click' :   alert ('ok');   break;    case 'load' :   document.addEventListener ('click', handler, false);   window.addEventListener ('unload', handler, false);   break;  case 'unload' :   document.removeEventListener ('click', handler, false);   window.removeEventListener ('unload', handler, false);   break;  } } window.addEventListener ('load', handler, false);

関連するQ&A