开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第7天,点击查看活动详情
vue3响应式原理
前面在介绍vue2的响应式原理中,我们已经介绍过vue数据响应式原理是通过数据劫持结合发布订阅者模式来实现的。其中在vue2中数据劫持是通过Object.defineProperty()来实现的,其中存在的问题是:
- 新增、删除对象属性,视图不会更新
- 通过下标修改数组,视图不会更新
vue2响应式原理可以参考我的另一篇文章vue2之数据绑定和响应式原理
而在vue3中关于数据劫持采用的是Proxy代理的方式,这种方式能解决上述两种存在的问题,下面我们来看一下Proxy是如何代理的。
Proxy
在vue3中使用Proxy来进行代理拦截,在拦截的时候有get,set,和
- get: 读取p的某个属性时调用
- set: 修改、增加p的某个属性时调用
- deleteProperty: 删除p的某个属性时调用
let person = {
name:"张三",
age:18
};
const p = new Proxy(person,{
//读取p的某个属性时调用
get(target, propName) {
console.log(`有人读取了p身上的${propName}属性`);
return target[propName];
},
//修改、增加p的某个属性时调用
set(target, propName, value) {
console.log(`有人修改了p身上的${propName}`);
target[propName] = value;
},
//删除p的某个属性时调用
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}`);
return delete target[propName];
}
});
修改p对象
p.name;
p.age = 20;
p.sex = '女';
delete p.sex;
console.log(p);
console.log(person);
效果如下:
可以看出来,上面vue2中存在的问题确实不存在了。
Reflect
在vue3内部,不仅通过proxy进行代理,而且还通过Reflect(反射)对源对象的属性进行操作,Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。
Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。通过修改某些Object方法的返回结果,让其变得更规范化。如Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
因此上面的代码还可以写成这种
let person = {
name:"张三",
age:18
};
const p = new Proxy(person,{
//读取p的某个属性时调用
get(target, propName) {
console.log(`有人读取了p身上的${propName}属性`);
return Reflect.get(target, propName);
},
//修改、增加p的某个属性时调用
set(target, propName, value) {
console.log(`有人修改了p身上的${propName}`);
Reflect.set(target, propName, value);
},
//删除p的某个属性时调用
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}`);
return Reflect.deleteProperty(target, propName);
}
});
p.name;
p.age = 20;
p.sex = '女';
delete p.sex;
console.log(p);
console.log(person);
效果如下: