• ベストアンサー

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

  • removeEventListenerの必要性

    参考にしているJavaScriptのソースで下記のような部分があったのですが、 (画面に描画をするプログラムの一部です。動きとしてはマウスの動きに合わせて模様が描かれて残像が残って消えていきます。) j(b)関数の中の一行目でdocument.removeEventListener("mousemove", j, !1); としてmousemoveのイベントリスナーを削除しているのが何故なのか解らず困っています。 メモリリークが発生するとかそういう問題なのでしょうか? ----------------------------------------------------------------------- <script type="text/javascript"> (function() { function j(b) { document.removeEventListener("mousemove", j, !1); document.removeEventListener("touchstart", j, !1); y(b); var g = l - p * 0.5, f = m - q * 0.5, a = Math.sqrt(g * g + f * f), b = l + g / a * 150, a = m + f / a * 150, g = Math.atan2(f, g); g += Math.PI * (0.5 + Math.random() * 0.5) * (Math.random() > 0.5 ? 1 : -1); for (f = 0; f < z; f++) { for (var e = A[f].f, c = 0; c < r; c++) { var d = e[c], h = Math.PI * 0.15 / r * c + g, k = Math.cos(h) * (r - c) * 2, h = Math.sin(h) * (r - c) * 2; d.x = b; d.y = a; d.d = k; d.e = h } j = !1 } document.addEventListener("mousemove", y, !1); document.addEventListener("touchmove", y, !1); document.addEventListener("touchstart", K, !1); setInterval(L, 1E3 / 30) } ------------------------------------------------------------------------- 同じソースの中で window.onload = function(){ ・・・   document.addEventListener("mousemove", j, !1); というようにイベントリスナーに登録しているところは見つかったので、これを削除しているのかとは思うのですが、 何分未熟なもので、それがどういう意図によるものなのか理解できません。 どなたか、知恵を貸して頂けないでしょうか?

  • JSのイベントターゲット が難しい

    JSのイベントターゲット (EventTarget)が難しくてよくわからないのですが初心者にもわかるように解説していただけるとありがたいです。 https://developer.mozilla.org/en-US/docs/Web/API/EventTarget イベントターゲット(EventTarget)は、DOMイベントを受け取り、それらへのリスナーを持つことが出来るオブジェクトによって実装されるDOMインターフェースです。 Elementと、 documentと、 windowは、ほとんどの共通イベントターゲットですが、 例えば、XMLHttpRequest、AudioNode、AudioContextなど、 他のオブジェクトもエベントターゲットになることが可能です。 多くのイベントターゲット(Element、document、windowを含む)は、 onXXXプロパティと属性を介して、 イベントハンドラの設定もサポートします。 メソッド .addEventListener() 要素にイベントハンドラを登録します。 .dispatchEvent() DOM内のノードのイベントを実行します。 .removeEventListener() EventTarget.addEventListenerを使用して登録されたイベントリスナーを削除します。 イベントを発動させる要素につけるイベントファンクションのようなものなのでしょうか?

  • 問題はbind の付いたリスナーを削除できないこと

    リンク先で下記のように書かれていますが、どういう意味でしょうか? >問題は、bind の付いたリスナーを削除できないということ ・「bind の付いたリスナーを削除」しないと何がマズいのでしょうか? ・thisの挙動が変わったままになるから? ・thisの挙動が変わるというのは、Somethingの中だけの話ではないのでしょうか? ・この場合のリスナーは? addEventListener('click', this.onclick2を指すのでしょうか? >リスナーを後で削除できるように、そのリスナーへの参照を残しておく必要があります ・「リスナーへの参照を残しておく」って、具体的にどういうことなのでしょうか? https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener

  • イベントリスナを調べる方法についての質問です。

    イベントリスナを調べる方法についての質問です。 現在twitterのページで使われているJavaScriptの挙動を分析しているのですが、コード量が非常に多く苦労しています。 ある要素にどのようなイベントリスナが追加されたか、または追加されているかということを調べるいい方法はないでしょうか? addEventListenerで関数を登録した場合、element.onclickにセットされた関数を取得するというような方法が使えないので困っています。 bookmarkletやユーザースクリプト、アドオンなど何でもいいので、要素に追加されているイベントリスナを直接調べたり、あるいはイベントリスナが追加される瞬間を検出できるようないい方法があれば教えてください。 (解析はFirefox上で行っていますが、他のブラウザを使う方法でも構いません) 宜しくお願いします。

  • Javascriptのオブジェクト指向プログラミングとイベント、thisの扱い

    Javascriptを勉強中です。 オブジェクト指向プログラミングを習得しようと努力しております。 あるHTML要素(例ではelm)にクリックイベントを付加する際、オブジェクト内のmyFuncを呼ぶのに以下のようにthis.myFuncとすると、thisがHTML要素となるためにエラーが出ます。 elm.addEventListener("click", this.myFunc, false); これを回避する目的で elm.addEventListener("click", (function(that) { return function() { that.myFunc(); } } )(this), false); とオブジェクト内からクロージャを使って定義することで解決することは分かったのですが、このイベントを削除するのに、 elm.removeEventListener("click", (function(that) { return function() { that.myFunc(); } } )(this), false); や elm.removeEventListener("click", function() { that.myFunc(); }, false); としても除去することが出来ません。この場合はどのようにイベントを削除することが出来るのでしょうか? そもそもクロージャを使った定義部分に問題があるのでしょうか? どうぞ教えていただきますようお願いいたします。

  • addEventListenerについて

    addEventListenerメソッドについてgoogleで検索してみていろいろと読んでみましたがいまいち理解できません。 ブラウザ上でのイベントとjavascriptの関数を結びつけるのが役割かなとはなんとなく分かりましたが、このメソッドの第3引数のtrue,falseが、キャプチャのオンかオフらしいのですが、キャプチャなるものが理解できません。 教えて下さい。よろしくお願いします。

  • 循環参照とメモリリークに関して

    次のスクリプトはメモリリークを起こしているでしょうか。 function process(listener){ return function(evt){ listener.call(evt.target,evt); }; } function addEvent(element,type,listener,useCapture){ element.addEventListener(element,type,process(listener),useCapture); } var div=document.getElementsByTagName('div')[0]; //存在するものとして addEvent(div,'click',function(){;},false); //いかにも起こしそう div.parentNode.removeChild(div); //親も存在するものとして 工夫してみたものの、やはりメモリリークするんでしょうか。 実際にaddEventListenerのlistener引数に渡されるのは、element変数を参照しない function(evt){ listener.call(evt.target,evt); }; ですが、listener変数は参照します。 そして、そのlistener変数はdiv変数(DOM)を参照するので、ここで循環するのでしょうか。 そして、以下の場合はどうなのでしょうか。。 var elements=[document.getElementsByTagName('div')[0]]; elements[0].addEventListener('click',function(){;},false); elements[0].parentNode.removeChild(elements[0]);

  • Now Loading+FLV_????? 教えてください!

    皆様、お世話になります。 以下、某Flash入門書に載っている簡単なNow Loadingのスクリプトです。 この本では、load完了後、jpegの写真が表示されます。 私は、load完了後に、自前のFLVを再生させたいと思い、既存のjpegを 自前のFLVに取り替えました。書き出すと、エラーが起こります。 以下、どのようにしたら、Now Loadingのカウントダウン後に、FLVが表示 できるでしょうか? ----------------------------------------------------------------------------------------------------------------- //イベントリスナーの登録 addEventListener(Event.ENTER_FRAME, loadCheck); stop(); function loadCheck(event:Event):void { //ロードされたパーセンテージを求める var percent:int = Math.ceil(loaderInfo.bytesLoaded / loaderInfo.bytesTotal * 100); //テキストボックスに表示 percentBox.text = percent + "%"; //100%ロードされたら if (percent >= 30) { //イベントリスナーを削除 removeEventListener(Event.ENTER_FRAME, loadCheck); //2フレーム以降に進む gotoAndPlay(2);; } } -----------------------------------------------------------------------------------------------------------------

    • ベストアンサー
    • Flash
  • addEventListenerの使い方について

    イベントリスナでスクロール時にアラートを表示したいのですが、 以下のソースでは動作しませんでした。 どこかに簡単なイベントに対するアクションを記載したサンプルコードはありますでしょうか? <script type="text/javascript"> document.addEventListener("scroll", alview, false); funciton alview(a){ alert(1); } </script> <body>

  • Actionscript3.0 子のイベントを削除

    Actionscript3.0で親のムービーから子のイベント指定して削除することは可能でしょうか? 親のステージに配置したmymcの中でballをENTER_FRAMEを使い動かしています。 親のステージに配置したbtnをクリックすることで、 ENTER_FRAMEを削除したいのですが、 下記のスクリプトだと、親のほうでmyenterframeが未定義と表示されてしまいます。 どのように記述すればよいのでしょうか? よろしくお願いいたします。 ーーーーーーーーーーーーーーーーー親ーーーーーーーーーーーーーーーーー btn.addEventListener (MouseEvent.CLICK, myclick); function myclick(event:MouseEvent):void{ mymc.removeEventListener(Event.ENTER_FRAME, myenterframe); } ーーーーーーーーーーーーーーーーーmymcーーーーーーーーーーーーーーーーー addEventListener(Event.ENTER_FRAME, myenterframe); function myenterframe(evt:Event):void { ball.x++; }

    • ベストアンサー
    • Flash