[javascript]同じthisを渡しているようにしか見えないが、実際には違うthisを渡している
Discussion
Closed
概要
他のプロジェクトで使われていたJSのコードを拝借した際にどういう処理をしているのか読んでいたところ、同じthisを渡しているようにしか見えないが、実際には違うthisを渡しているコードを見つけました。これがどうにもわかりづらく腑に落ちないため意見をお聞きしたいです。
該当のコード
以下は簡略化したものです。
export default class {
constructor (target) {
this.target = target
}
initialize () {
this.addEventListener()
}
hello () {
console.log('hello')
}
addEventListener () {
this.target.addEventListener('blur', this.hello.bind(this))
}
}
ここで注目していただきたいのは、this.hello.bind(this)
です。どうやらこれhello呼び出し元のthisと引数のthisは違うものを指していると思われるのです。
わかりやすくするため、下記コードに書き換えてみます。
this.target.addEventListener('blur', function (e) {
this.hello()
}.bind(this))
ハンドラー内のthis.hello()
のthisは本来はイベントが起きた要素(target)を指す(参考) のですが、bind(this)によってこのClass自体のthisで矯正しているため、結果としてClass内で定義したhello()が実行できています。
裏付け
hello呼び出し元のthisと引数のthisは違うものを指していると思われる
上記仮説の裏付けとして下記のようにbind(this)を外してみます。
addEventListener () {
this.target.addEventListener('blur', this.hello())
}
この状態でブラウザ上のtargetからフォーカスを外してみてもhello()は実行されません。
これはthisがtargetを指しているがtargetはhello()が定義されていないためだと考えられます。
腑に落ちない点
functionで書き換えれば理解はできるが、this.hello.bind(this)
の形だとthisが同じものを指しているようにしか見えないため、こういう書き方ができちゃうのって可読性的にどうなの?という点です。(JSに慣れている人は気にならない?)
これはjavascriptの仕様上、もといaddEventListner関数の仕様上仕方のない部分なのでしょうか?