详解Vue数据响应式原理之数组
什么是Vue数据响应式?
Vue.js是一款MVVM框架,它通过数据绑定和组件化来构建用户界面。Vue的核心是将DOM和数据进行绑定,当数据发生变化时,DOM会自动更新,这就是Vue的数据响应式。
数组响应式的特殊性
数组在JS中是引用类型,当我们对一个数组进行变更时,比如push、pop、splice等操作,Vue是无法检测这些变化的。因此Vue提供了一些特殊的方法来实现数组响应式,包括push、pop、shift、unshift、splice、sort、reverse这些方法。
这些方法都会触发数组的更新,也就是数组内部的_observer会进行notify,再更新对应的DOM。
数组响应式的实现原理
Vue在初始化时会对所有的data进行递归遍历,并使用Object.defineProperty方法将属性变为getter/setter。在通过getter获取属性值时,Vue会收集当前Watcher,并推到Dep.target中,当属性变化时,setter会通知Dep,再通知Watcher更新DOM。
具体到数组上,Vue并没有使用Object.defineProperty来劫持数组上的方法。因为数组的方法是可以通过索引位置修改数组的元素的值的,如果使用Object.defineProperty劫持方法,会导致更新的粒度过细,性能不好。
Vue在劫持数组方法时,使用了另外一种方法,即重写数组上的方法。Vue重写数组上的这些方法,仍旧执行原方法的逻辑,最后再手动触发数组的通知更新,比如触发 _observer.notify(),从而告知Watcher有更新了,Watcher就可以更新对应的DOM。
下面是Vue内部对数组的劫持方式的代码实现:
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {
// 缓存原始方法
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this._observer
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
ob.notify()
return result
})
})
通过重写数组上的这些方法,Vue就能够实现数组响应式了。
示例说明
下面给出两个示例来说明Vue数组响应式的实现方式。
push方法
当我们使用数组的push方法添加一个新元素时,Vue会先判断该数组是否为被劫持过的数组,然后再触发原生的push方法,最后再手动触发数组的通知更新。
const arr = []
const ob = arr._observer // 这里 ob 指的是数组被监测到的Observer实例对象
arr.push(1)
// 调用原生push方法后 arr 变成 [1],同时会手动触发 ob.notify(),通知所有Watcher更新对应的DOM
splice方法
当我们使用数组的splice方法删除一个元素时,Vue会先判断该数组是否为被劫持过的数组,然后再触发原生的splice方法,最后再手动触发数组的通知更新。
const arr = [1, 2, 3]
const ob = arr._observer // 这里 ob 指的是数组被监测到的Observer实例对象
arr.splice(1, 1)
// 调用原生splice方法后 arr 变成 [1, 3],同时会手动触发 ob.notify(),通知所有Watcher更新对应的DOM
以上就是Vue数组响应式的实现方式以及示例说明。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解vue数据响应式原理之数组 - Python技术站