vue数组实现原理
Vue 数组响应式原理
Vue 通过重写数组的原型方法来实现对数组变化的监听。Vue 没有直接监听数组的索引变化,而是通过拦截数组的变异方法(如 push、pop、splice 等)来触发视图更新。
实现机制
Vue 创建了一个继承自 Array.prototype 的新对象,并重写了其中的变异方法。当调用这些方法时,Vue 会先执行原始数组方法,然后触发依赖更新。
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
ob.dep.notify()
return result
})
})
数组响应式处理流程
-
初始化阶段
Vue 在初始化数据时,会遍历数组的每个元素,对非原始值进行响应式处理。 -
方法拦截
当调用数组的变异方法时,Vue 会先执行原始操作,然后对新插入的元素进行响应式处理,最后通知依赖更新。 -
依赖收集
数组的依赖收集通过__ob__属性完成,每个响应式数组都会有一个关联的Observer实例。
注意事项
- 直接通过索引修改数组元素(如
arr[0] = newValue)不会触发视图更新,需使用Vue.set或this.$set。 - 修改数组长度(如
arr.length = 0)同样不会触发更新。 - 对于非变异方法(如
concat、slice),Vue 不会拦截,但返回的新数组如果是响应式的,其元素会被处理。
替代方案
对于需要深度监听或复杂数组操作的情况,可以使用以下方式:
- 使用
Vue.set或this.$set修改数组元素 - 使用
splice方法替代直接赋值 - 对于大规模数据更新,考虑使用
this.$forceUpdate()(不推荐频繁使用)







