class Demo { constructor() { this.num = 1 this.init() } resize() { alert(this.num) } init() { window.addEventListener('resize', this.resize) } } new Demo()
代碼執行後,縮放瀏覽器,此時彈窗顯示 undefined
。vue
符合預期!!git
import Vue from 'vue' new Vue({ template: '<div></div>', data: { num: 1 }, methods: { resize() { alert(this.num) } }, mounted() { window.addEventListener('resize', this.resize) } }).$mount('#app')
縮放瀏覽器,此時彈框顯示 1
。github
不符合預期!!瀏覽器
按常理,綁定事件 this.resize
後,將會丟失 this
所指向的上下文,因此第一個代碼執行的結果是 undefined
。app
所以猜測,在 Vue 的實現版本中,綁定是必定不是定義在 methods
下的 resize
方法。oop
src/core/instance/state.js#L258源碼分析
function initMethods (vm: Component, methods: Object) { const props = vm.$options.props for (const key in methods) { // ... vm[key] = methods[key] == null ? noop : bind(methods[key], vm) } }
能夠看到在 Vue 實例上綁定的方法,都是被 bind
處理過的。this
src/shared/util.js#L203prototype
function polyfillBind (fn: Function, ctx: Object): Function { function boundFn (a) { const l = arguments.length return l ? l > 1 ? fn.apply(ctx, arguments) : fn.call(ctx, a) : fn.call(ctx) } boundFn._length = fn.length return boundFn } function nativeBind (fn: Function, ctx: Object): Function { return fn.bind(ctx) } export const bind = Function.prototype.bind ? nativeBind : polyfillBind
因而可知, Vue 的實例調用的方法,是通過 bind
後帶有上下文的新方法。code