起源
通过 Class 实现代码
class Demo {
constructor() {
this.num = 1
this.init()
}
resize() {
alert(this.num)
}
init() {
window.addEventListener('resize', this.resize)
}
}
new Demo()
代码执行后,缩放浏览器,此时弹窗显示 undefined
。
符合预期!!
通过 Vue 实现的代码
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
。
不符合预期!!
代码分析
按常理,绑定事件 this.resize
后,将会丢失 this
所指向的上下文,所以第一个代码执行的结果是 undefined
。
因此猜想,在 Vue 的实现版本中,绑定是一定不是定义在 methods
下的 resize
方法。
源码分析
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
处理过的。
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
后带有上下文的新方法。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。