今天在 Vue 中尝试绑定 Lodash 防抖动函数 (debounce), 在传入闭包函数的时候遇到了一点问题, 其实是对箭头函数和引用传递的机制理解不够.
出现问题的代码:
import _ from 'lodash'
export default {
methods: {
contentChanged: _.debounce(() => {
console.log(this.content)
}, 2000)
}
}
这里我还特地考虑了箭头函数的作用域问题, 因为箭头函数不会重新绑定作用域, 我特地使用了箭头函数, 希望能够取到当前 Vue 实例的 post 属性, 结果输出的却是 undefined
.
在将箭头函数改为普通函数后, this
反而可以正确指向 Vue 对象:
import _ from 'lodash'
export default {
methods: {
contentChanged: _.debounce(function () {
console.log(this.content)
}, 2000)
}
}
这让我有点困惑, 因为之前对箭头函数作过试验, 文档 Arrow Functions 中使用的例子是可以正确复现的, 箭头函数不重新绑定作用域是毫无疑问的:
function Person() {
this.age = 0;
setInterval(() => {
this.age++;
}, 1000);
}
这个例子和上述场景的区别在于函数没有被传递.
在函数被传递后, 如果使用了箭头函数, this
最终将指向其定义处上下文的 this
对象, 要注意的是, 上述箭头函数是在防抖动函数被调用的时候定义的 (而不是代码所在的位置), 显然上述函数不是在当前作用域中被调用, 因此 this
肯定不是当前 Vue 实例.
而如果使用了普通函数, this
当然也不是直接指向当前 Vue 实例, 但是在 Lodash 中使用了 Function.apply()
方法, 将其作用域重新绑定到调用防抖动函数的上下文, 也就是当前 Vue 实例, 修正 this
的引用对象.
箭头函数和普通函数一个很大的区别在于箭头函数不仅不重新绑定作用域, 而且箭头函数的作用域不可以被重新绑定, 这是造成上述行为差异的原因.
可以看这一篇讨论: 关于箭头函数this的理解几乎完全是错误的.
有一句话说得非常清楚:
"箭头函数" 的 this
, 总是指向定义时所在的对象, 而不是运行时所在的对象
Reference
Throttling and Debouncing Events with Vue.js and lodash
0526