北京专业制作网站的公司wiki网站开发工具
在 Vue2 中,响应式系统是通过 Object.defineProperty 实现的,它可以劫持对象的属性 getter/setter,但有两个大问题:
- 不能监听数组的索引变动(
arr[0] = xxx无法触发更新)。 - 不能监听数组的 length 变化(
arr.length = 0无法触发更新)。
🔑 Vue2 的解决办法
Vue2 在初始化时,会 重写数组的 7 个变更方法,让它们在调用时不仅修改数据,还能通知视图更新。
这 7 个方法是:
pushpopshiftunshiftsplicesortreverse
实现思路:
-
拿到数组原型上的方法(
Array.prototype.push等)。 -
新建一个对象,继承
Array.prototype。 -
在这个对象上重写上面 7 个方法:
- 调用原始方法完成数据修改;
- 手动触发
dep.notify(),告诉依赖进行视图更新。
源码简化版(伪代码)
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {arrayMethods[method] = function (...args) {// 先调用原始方法const result = arrayProto[method].apply(this, args);// 通知依赖更新this.__ob__.dep.notify();return result;}});
当 Vue2 检测到一个属性是数组时,就会把它的原型指向 arrayMethods,从而拦截这几个操作。
🔒 局限性
- 直接修改数组索引:
vm.arr[1] = 100不会触发更新。 - 修改
length:vm.arr.length = 0不会触发更新。
解决办法:
- 使用
Vue.set(vm.arr, index, value)或this.$set(vm.arr, index, value)。 - 使用
splice替代:vm.arr.splice(index, 1, value)。
🆕 Vue3 的变化
Vue3 用 Proxy 重写了响应式系统,能直接监听数组的索引和 length 变化,不需要像 Vue2 那样 hack。
👉 总结:
Vue2 通过重写数组的 7 个变更方法来解决数组监听问题,但索引和 length 的变动仍然无法直接监听,只能用
Vue.set或splice替代。Vue3 使用 Proxy 完美解决了这个限制。
