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