1 vue2响应式数据原理
vue2:通过es5的Object.defineProperty实现数据响应式
// 数组响应式处理:覆盖原有数组原型方法,增加通知变更
var originProto = Array.prototype
// 创建一个含有原型的对象
var arrayProto = Object.create(originProto);
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(key => {
arrayProto[key] = function() {
originProto[key].apply(this, arguments)
// 通知更新视图代码...
}
})
// 响应式数据处理
function defineReactive(target, key, val) {
// 子属性若是对象,也需要加入响应式系统中(递归)
observe(val)
Object.defineProperty(target, key, {
get() {
// 收集依赖代码...
return val
},
set(newVal) {
if (val !== newVal) {
// 子属性若是对象变更,需要重新加入响应式系统
observe(newVal)
val = newVal
// 通知更新视图代码...
}
}
})
}
// 响应式系统
function observe(obj) {
if (typeof obj != 'object' || obj == null) return
// 对象成员若是数组,则修改原型方法
if (Array.isArray(obj)) {
Object.setPrototypeOf(obj, arrayProto)
}else{
// 遍历对象属性
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
}
2 vue2响应式数据的缺点
- 递归遍历数据对象属性,消耗大
- 新增/删除属性,数据无响应;需要额外方法实现(Vue.set/Vue.delete)
- 数组修改需要额外方法实现(Vue.set),或者通过重写的push/pop/shift/unshift/splice/sort/reverse方法实现;
3 vue3响应式数据原理
通过es6的Proxy代理对源数据的操作可以解决vue2响应式数据的缺点
function defineReactive(obj) {
if (typeof obj !== 'object') return obj
return new Proxy(obj, {
get(target, key, receiver) {
// 收集依赖代码...
var res = Reflect.get(target, key, receiver)
// 子属性若是对象,需要代理子属性,注:只有使用了该子属性才会执行是否要递归代理
return (typeof res === 'object') ? defineReactive(res) : res
},
set(target, key, val) {
Reflect.set(target, key, val)
// 通知更新视图代码...
},
deleteProperty(target, key) {
Reflect.deleteProperty(target, key)
// 通知更新视图代码...
}
})
}