Vue.js における methods の this は自動的に VM に束縛される
執筆当時の環境
- Vue.js v1.0.17
JavaScript で以下の様なコードを書いた時、onResize
内の this
はグローバルオブジェクト (window
) となり、this.log('resized')
はエラーとなります。
const obj = {
log: function (str) {
console.log(str)
},
onResize: function (event) {
this.log('resized')
},
}
window.addEventListener('resize', obj.onResize) // this.log('resized') でエラー
上記のコードの obj
を、以下のように Vue.js の VM にするとエラーが起きなくなり、意図した通りに動作するようになります。また、this
の値は obj
に束縛されています。
const obj = new Vue({
methods: {
log: function (str) {
console.log(str)
},
onResize: function (event) {
this.log('resized')
},
},
})
window.addEventListener('resize', obj.onResize) // エラーが発生しない
このことから、Vue.js では methods に渡された関数を VM に束縛していると言えます。実際にコードを追って確かめてみます。
methods で Github のリポジトリを検索すると、 _initMethods
というメソッドが存在しているのがわかります。このメソッドは src/instance/internal/state.js
の中に定義されています。_initMethods
の中を見てみると、bind(methods[key], this)
という記述があります。JavaScript ネイティブの bind
ではないですが、どうやらここで this
を束縛しているように見えます。
vue/state.js at 521e8d2754c2e7f172c3c9702fdb74fe993027fb · vuejs/vue
なぜわざわざ独自の bind 関数を使っているのかを調べるために、この bind
の定義も見てみました。bind
は src/util/lang.js
に定義されています。
vue/lang.js at 521e8d2754c2e7f172c3c9702fdb74fe993027fb · vuejs/vue
関数の上のコメントには、ネイティブの bind よりも早いと書いてあります。少し調べてみたところネイティブの bind は、this の束縛の他に型チェックや、引数の束縛なども行うため遅くなっているとのことでした。ただ、遅いとはいってもほとんどのケースでは気にならない違いだと思うので、普通にアプリケーションを作る際には気にしなくても良さそうです。
javascript - Why is bind slower than a closure? - Stack Overflow