JavaScriptの動かないコード (中級編) イベントハンドラに同じ関数を2回以上追加したい
以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)
やりたい事:
- ボタン押下時に, 2 と表示する。
- そのために,0に1足す操作を2回行なう。
<input type="button" value="「2」と表示" id="my_button"> <!-- ここに表示されます --> <div id="my_div"></div> <script language="JavaScript"> // 初期化 var a = 0; // a に1足して表示 function f(){ a++; my_div.innerHTML = a; } // イベント追加用の関数 function addEvent( element, eventName, func ){ if ( element.addEventListener ) { // Firefox element.addEventListener( eventName, func, false ); } else if ( element.attachEvent ) { // IE element.attachEvent( "on" + eventName, func ); } } // イベントを2個追加 addEvent( my_button, "click", f ); addEvent( my_button, "click", f ); </script>
答え
IEでは「2」と表示される。
しかし,Firefoxでは「1」と表示されてしまう。
IEでは,イベントリスナとして同じ関数を2回以上追加する事が可能だ。
一方FFでは,関数の重複が無視されてしまい,同一の関数を複数回追加しても一度しか実行されないようだ。
WEB ページの onLoad イベントのまとめ
http://winofsql.jp/VA003334/JScript08...
IE は、同じ関数でも追加されますが、Firefox と Opera は、同じ関数は追加されないようです※ 但し実行順序から考えると、同じ関数の追加は Firefox は無視。Opera は以前のを削除して追加のようです
Mozillaのページにも公式に述べられている。
element.addEventListener
https://developer.mozilla.org/ja/DOM/...
複数の同一のイベントリスナー
複数の同一の EventListener が、同じ EventTarget に同じ引数で登録された場合、重複するインスタンスは反映されません。EventListener が 2 度呼び出されることはなく、重複するインスタンスは反映されないので、removeEventListener で手動で削除する必要はありません。
ライブラリを利用した場合は,多少挙動が変わってくる。
jQueryで動的にイベント追加したいという場合,例えばクリック専用の click() を使って
$( "#my_button" ).click( f ); $( "#my_button" ).click( f );
としてみたり,あるいは bind() を使って
$( "#my_button" ).bind( "click", f ); $( "#my_button" ).bind( "click", f );
のようにイベントハンドラを2回割り当てたとする。
でも,いずれの場合でも,IE・FFの両者で,f() は一度しか実行されない。(二度にはならない。)
prototype.jsを使ってもだめである。
Event.observe( my_button, "click", f ); Event.observe( my_button, "click", f );
のようにしても,IE・FFの両者で,f() は一度しか実行されない。
クロスブラウザで,同じ関数を複数回イベントハンドラに割り当てるには,下記のようにする方法がある。
addEvent( my_button, "click", function(){f();} ); addEvent( my_button, "click", function(){f();} );
f という関数を直接割り当てるのではなく,新たに関数オブジェクトを作成して,その関数オブジェクトを毎回,別個に割り当てるようにすればよいのだ。
こうすれば,FFでも f() は無事2回実行され,「2」と表示されるようになる。
(※ただし,これだと追加したリスナに名前がついていないので,イベントを削除したい時には困る。)