vue重写了push、pop、shift、unshift、splice、sort、reverse这7个变异方法,因它们直接修改原数组结构且需触发依赖更新;通过继承array.prototype并覆盖方法,在执行原逻辑后递归响应式处理新增元素并通知更新。

Vue.js 的响应式数据绑定在数组上不能靠 Object.defineProperty 自动捕获变化,因为数组的索引赋值(如 arr[0] = x)和 length 修改不会触发 setter。所以 Vue 必须主动干预——重写那 7 个会改变原数组内容的方法,让它们在执行完原逻辑后,主动通知依赖更新。
哪些数组方法被重写了
Vue 重写了以下 7 个**变异方法(mutating methods)**:
pushpopshiftunshiftsplicesortreverse
这些是唯一能直接修改数组自身结构(长度、元素顺序、内容)的原生方法。Vue 没有重写 filter、map、slice 等返回新数组的方法——它们本来就不改原数组,自然不需拦截;也不处理 arr[2] = x 或 arr.length = 0 这类操作,因为底层无法劫持。
重写是怎么做的
核心是在 Array.prototype 上“造一层代理”:
- 创建一个继承自原生原型的新对象
arrayMethods - 对上述 7 个方法逐个用
Object.defineProperty覆盖,定义自己的mutator函数 - 每个
mutator先调用原生方法(保证功能不变),再做两件事:
– 若新增了元素(如push、unshift、splice插入),递归将新元素转为响应式(调用ob.observeArray(inserted))
– 最后触发依赖通知(ob.dep.notify()),让视图更新
为什么只重写这 7 个
因为只有它们满足两个关键条件:
- 直接修改当前数组实例(不是返回新数组)
- 会导致数组的响应式状态发生实质性变化(比如长度变、元素增删、顺序调整)
像 concat、slice 返回的是新数组,原数组没变,自然无需通知;而 arr[0] = 'x' 虽然改了内容,但 JS 引擎层面不触发任何可观测钩子,Vue 也无法拦截——这就是为什么 Vue 文档明确建议用 Vue.set(arr, index, value) 或 arr.splice(index, 1, value) 来确保响应式生效。
实际开发中要注意什么
理解重写机制后,日常编码要避开“响应式盲区”:
- 避免直接通过索引设置项:
vm.items[0] = newValue→ 改用vm.$set(vm.items, 0, newValue)或vm.items.splice(0, 1, newValue) - 避免直接修改
length:vm.items.length = 0→ 改用vm.items.splice(0) - 注意解构或展开运算符会丢失响应式:
const newArr = [...vm.items]是普通数组,后续变化不触发更新
本质上,Vue 的数组响应式不是“监听所有变化”,而是“精准包裹已知变更入口”。设计如此,既保证了性能可控,又覆盖了绝大多数真实场景。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











