イベントリスナーの登録

見出し右端の記号は?

Web Page
Booskanium's Tips.
忘れっぽい落書き人のメモ

JavaScriptのイベントリスナー設定の関数名でかっこ無し、HTMLのイベント属性への設定は関数名かっこ有りと暗記していませんか。
検索するとその理由まで解説しているコンテンツが少ないですね。
でもイベントリスナーに設定する関数名かっこ有り(引数指定有り)にしたい場面があるんですよ。
これはここの落書き人が有ることに嵌ってしまって気付かされて事です。

イベントリスナーに登録する関数

イベントリスナーの構文は下記のとおりです。

target.addEventListener(type, listener[, options]);

この構文の「listener」については「指定された型のイベントが発生するときに通知 (Event インターフェースに準拠しているオブジェクト) を受け取るオブジェクト。」と書いてあります。

具体的には関数オブジェクトを指定します。ここで巷に溢れている例では「関数名をかっこ無しで書け」とい唱えています。それは関数名の中身(関数オブジェクト)を代入(コピー)しなさいという意味です。
具体的に呼び出したい関数名がfuncなら下記の様に書くのが巷に溢れている例です。

target.addEventListener(type, func [, options]);
ちなみに、ここで「func()」と書くと、イベントリスナーには、func()が即実行され、その戻り値がイベントリスナーに設定されることになり、あれれとなります。まあ、トリッキー大好きな人には、可読性最悪にする手段でもあります。

巷に溢れている例ではコピーされますので、エベントが発生すると関数を記述したところのコード実行されるのではなく、イベントリスナーにコピー登録された関数が実行されるという意味です。
これで困るのは、関数中でthisを用いていたときです。オブジェクトリテラル中に記述されていると関数でthisを使っている場合に、イベントリスナー中にコピーされた関数は、そのオブジェクトリテラルが示すthisではありません。documentオブジェクトを示しています。

※つまりファンクションリテラル指定がベター

そこで落書き人は、オブジェクトリテラルの変数がobjで、そのリテラル中に記述されている関数がfuncなら以下の様に記述しています。
target.addEventListener(type, function(e){ obj.func(e); } [, options]);;
上記で関数の引数にeと書いているのは、イベント発生したオブジェクトを明示的に引き渡す事をはっきりさせています。
なお以下のように、複数の関数を順番に処理させることも出来ます。
target.addEventListener(type, function(e){ obj.func1(e);  obj.func2(e);} [, options]);;

上記を確認するコードです

オブジェクトリテラルの中に書いてある関数をリスナーに設定した時に、そのオブジェクトリテラルの中でthisが何を示すかで、使い勝手が違います。
下記はそれを確認するコードです。

var vari1 = "グローバル"; 
var setJob {
	vari1: "へのへのもへじ",
	func1: function() {
		consol.log(this.vari1);
	}
}
window.addEventListener('load',setJob.func1; },false);

この記述ではsetJobの中のfunc1を呼んだのに、"グローバルがコンソールに出力されます。
window.addEventListenerにセットされている関数の中身は、リスナー登録した時の、setJob.func1の中身がコピーされたものが実行されるからです。
では次は下記のように書いてみましょう。

var vari1 = "グローバル"; 
var setJob {
	vari1: "へのへのもへじ",
	func1: function() {
		consol.log(this.vari1);
	}
}
window.addEventListener('load',function(){ setJob.func1(); },false);

今度は"へのへのもへじ"がコンソールに出力されます。
なぜかといえば、後者はsetJobの中のfunc1が呼び出されるからです。
この説明でチンプンカンプンだ。という人は、もう一度最初から理解しながら読みななおしてください。
これもJavaScriptのthisの罠のひとつです。良く言えば柔軟性が高い、悪く言えばJavaScriptを難解に感じてしまう。

実は、この仕様の理解の妨げになるのが、デベロッパーツールのデバッカーです。イベントリスナーに関数記述が代入されているのに、デバッカーは関数の記述元で動いているかのように見せてくれます。このJavaScriptのデバッカーの見せ方を理解していなかった落書き人には、これがなんとも難解にみえました。