此题非常好,既考察深度又考察广度,面试者要对两个版本的响应式原理都有深入理解才能答好。
vue2数据响应式实现根据对象类型做不同处理,如果是object,则通过Object.defineProperty(obj,key,descriptor)
拦截对象属性访问
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
return val
},
set(v) {
val = v
notify()
}
})
}
如果是数组,则覆盖数组的7个变更方法实现变更通知
const arrayProto = Array.prototype
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)
notify()
return result
})
})
可以看到vue2中有几个问题:
vue3中为了解决以上问题,使用原生的Proxy代替:
function defineReactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key)
return Reflect.get(target, key)
},
set(target, key, val) {
Reflect.set(target, key, val)
trigger(target, key)
},
deleteProperty(target, key) {
Reflect.deleteProperty(target, key)
trigger(target, key)
}
})
}
可以同时支持object和array,动态属性增、删都可以拦截,新增数据结构均支持,对象嵌套属性运行时递归,用到才代理,也不需要维护特别多的依赖关系,性能取得很大进步。