vue 是如何深度监听data的变化的
2021-08-04 本文已影响0人
菜鸟切图仔
调用observer函数,传入data,observer(data),遍历data每一个属性,调用defineReactive(target,key,target[key]),defineReactive里通过Object.defineProperty 对target 上的key属性进行get、set的拦截,在set里触发视图更新
// 设置数据劫持,设置数据响应式
function defineReactive(target,key,target[key]){
// 深度监听
observer(value);
// 核心 API
Object.defineProperty(target,key,{
get(){
return value
},
set(newValue){
if(newValue!==value){
// 深度监听
observer(value)
value=newValue;
// 触发更新
updateView()
}
}
})
}
// 监听data属性
function observer(target){
if(typeof target !== 'object' || target===null){
// 不是对象或者数组,直接返回
return target;
}
// 如果是数组,更改该对象的原型
if (Array.isArray(target)) {
target.__proto__ = arrProto;
}
for(let key in target){
defineReactive(target,key,target[key])
}
}
// 更新视图
function updateView(){
console.log("更新视图")
}
const data = {
name:"Lili",
age:20
}
observer(data)
如何实现数组的监听
1、重写数组原型方法
2、observer 函数中,若属性为数组,则更改数组属性的proto为重写后的数组对象
// 重新定义数组原型
function reWriteArrayProperty() {
const oldArrayProperty = Array.prototype;
const arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach((key) => {
arrProto[key] = function () {
updateView();
oldArrayProperty[key].call(this, ...arguments);
};
});
return arrProto;
}
// 监听data属性
function observer(target) {
if (typeof target !== 'object' || target === null) {
// 不是对象或者数组,直接返回
return target;
}
// 如果是数组,更改该对象的原型
if (Array.isArray(target)) {
target.__proto__ = reWriteArrayProperty();
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
Object.defineProperty 的缺点
1、深度监听,需要递归到底,一次性计算量大
2、新增属性、删除属性,监听不到
3、无法监听数组,需要改写数组原生方法,然后改变数组的原型
data.x = 2; // 监听不到属性x的新增,Vue.set
delete data.x ; // 监听不到属性x的删除,Vue.delete