addEventListenerのhandleEventについて
オブジェクト(指向)で使うようです。
syntax
プロパティにhandleEventがあるオブジェクトを第二引数に渡す。
handleEventの値はfunction
// 変数に入れて var foo = { val: 1, handleEvent(ev) { console.log(this.val++) } } document.addEventListener('click', foo) document.removeEventListener("click", foo) // removeできる // 直接 document.addEventListener('click', { val: 1, handleEvent(ev) { console.log(this.val++) } })
this.handleEventが参照されるので、継承では近いものになる。
function Foo(){} Foo.prototype.handleEvent = function() { console.log(1) } var foo = new Foo() document.addEventListener("click", foo) // ↑ Foo.prototype.handleEventが呼ばれる // ↓ foo.handleEventが呼ばれる foo.handleEvent = function() { console.log(2) }
使う利点は何か
this
はイベントリスナ内でevent.currentTarget
を指す。
handleEvent
ではオブジェクトに固定される
handleEventを使わない場合
var o = { str: "hello", foo: function() { alert(this.str) } } o.foo() // "hello" document.addEventListener("click", o.foo) // undefined
イベントリスナはthisの参照がdocumentになり、o.fooはdocument.foo
になるのでundefined
に。
handleEventを使った場合
var obj = { str: "hello", handleEvent: function() { alert(this.str) } } o.handleEvent() // "hello" document.addEventListener("click", obj) // "hello"
this
の呼び出しがobj
に固定された。
使う必要は無い
handleEvent
を使わなくても同じことはできる。
Array#map
みたいなあれば便利だけど、無いなら無いでどうにかなる系だと思う。
thisを固定するひと手間がかかるので、使うにこしたことは無いのだけれど。
必要かという点で見れば、必要でないメソッドは沢山あるので深く考えない方が良いと思う(´ω`)
オブジェクトの例
var obj = { str: "hello", fn: function() { alert(this.str) } } // thisの呼び出しを固定するひと手間 var listener = function() { obj.fn() } document.addEventListener("click", listener) document.removeEventListener("click", listener)
MDNに載っている例のせいかbind
と比較されることが多いけれど、
bind
でもイベントリスナを変数に代入すればremoveできる。
コンストラクタの例
3つの異なる書き方を比較する。どれも同じことをしている。
handleEvent + コンストラクタ
function Foo(element, str) { this.str = str this.element = element } Foo.prototype.handleEvent = function(evt) { alert(this) } Foo.prototype.init = function() { this.element.addEventListener('click', this) } Foo.prototype.cancel = function() { this.element.removeEventListener('click', this) } var foo = new Foo(document, "hello") foo.init() foo.cancel() Foo.prototype.handleEvent = function(){} // 全体のcallbackを書き換え foo.handleEvent = function(){} // 個別に書き換え
記述が一番短い
function + コンストラクタ
function Foo(element, str) { this.element = element this.str = str } Foo.prototype.handle = function(e) { alert(this.str) } Foo.prototype.init = function() { var _this = this this.listener = function(e){ _this.handle(e, this) } this.element.addEventListener('click', this.listener) } Foo.prototype.cancel = function() { this.element.removeEventListener('click', this.listener) } var foo = new Foo(document, "hello") foo.init() foo.cancel() // やっぱり書き換え可能 Foo.prototype.handle = function(){} foo.handle = function(){}
いちいち新しい関数を作るので効率は悪い。継承の利点の一つが失われている。
その点を除けばhandleEvent
と同等のことができる。
bind + コンストラクタ
Foo.prototype.init = function() { this.listener = this.handle.bind(this) this.element.addEventListener('click', this.listener) }
後からイベントリスナのcallbackを書き換えることは不可能。でもremoveはできる。
(でも書き換えなんて実際するかどうか)
ということで、handleEvent
でしかできないことがあるのか考えたけど思いつかなかった。他の方法でわざわざ遠回りすることもないので、オブジェクトなら素直に使うということで。