vue2中使用的是 Object.defineProperty 方法对属性进行的监听,对原始对象进行操作
- 由于是针对属性的监听,所以每次监听都需要深度遍历对象进行监听属性的变化
- 会有效率的损失
- 在观察函数中 obj 的初始值都会被监听, 新增的属性无法被监听到;监听的步骤已经结束
const obj = {
a: 1,
b: 2,
c: {
c1: 20,
c2: 30,
},
}
// 判断是否是一个对象
function _isObjeck(v) {
return typeof v === 'object' && v !== null;
}
function observe(obj) {
for (const k in obj) {
let v = obj[k];
if (_isObjeck(v)) {
observe(v)
};
Object.defineProperty(obj, k, {
// get 用于读取数据
get() {
console.log("读取:", v)
return v;
},
// set 用于修改值
set(newVal) {
if (newVal !== v) {
console.log(`修改了属性${k}:`, newVal)
v = newVal;
}
},
});
}
}
// 观察
observe(obj)
obj.a = 20;
vue3 使用es6 proxy事件代理对数据代理一个新的对象,通过代理对象通知原始对象
- 不再对obj的某个属性进行监听,而是直接监听obj对象
- 由于不再是监听属性,所以不用不用遍历对象,直接监听对象
const obj = {
a: 1,
b: 2,
c: {
c1: 20,
c2: 30,
},
}
// 判断是否是一个对象
function _isObjeck(v) {
return typeof v === 'object' && v !== null;
}
//观察
function observe(obj) {
const proxy = new Proxy(obj,{
// target:obj对象 k:key val:修改后得值
get(target,k) {
let v = target[k];
if(_isObjeck(v)){
v = observe(v);
};
console.log("读取:", v)
return v;
},
// 修改值触发set
set(target,k,val) {
if(target[k] !== val){
console.log(`修改了属性${k}:`, val)
target[k] = val;
}
},
// 删除方法
deleteProperty(target, property) {
console.log('53:',target, property)
}
})
return proxy;
}
const proxy = observe(obj);
proxy.c.c1 = 30;
总结
无论是vue2还是vue3,必须要读取的值变成get,set函数,只能通过get,set函数对值进行监听/操作