一、回顾Vue2
1、Vue2中的响应式原理
- 对象类型:通过Object.defineProperty()对属性的读取丶修改进行拦截(数据劫持)
- 数组类型:通过重写更新数组的一系列方法来实现拦截。
let person = {
name:'蔡徐坤',
age:18
}
let p = {}
Object.defineProperty(p, "name", {
get(){ //有人读取name时调用
return person.name;
},
set(value){ //有人修改name时调用
console.log("有人修改了name属性")
person.name = value
}
});
Object.defineProperty(p, "age", {
get(){ //有人读取age时调用
return person.age;
},
set(value){ //有人修改age时调用
console.log("有人修改了age属性")
person.age = value
}
});
此时,p对象就完成了对person对象的代理,当读取p.name时,实际上是在读取person.name,当修改p.name时,实际上person中name属性的值也会随之更新。
2、vue2的响应式的一些问题
1.新增属性,或者删除属性,界面不会更新(解决方法:利用delete)
2.直接通过下标修改数组,界面不会自动更新(解决方法:利用$set、splice())
二、Vue3中的响应式原理
1、原理
- 通过Proxy(代理):拦截对象中任意属性的变化,包括属性的读写,属性的添加,属性的删除等。
- 通过Reflect(反射):对源对象的属性进行操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
//源数据
let obj = {
name:'蔡徐坤',
age:18
}
// 模拟vue3中的响应式
//Proxy第一个参数是源数据。第二个参数是配置
const p = new Proxy(obj,{
// 读取
get(target,propName){
console.log(`读取了p的${propName}属性`)
//反射
return Reflect.get(target,propName)
},
// 修改,新增
set(target,propName,value){
console.log(`修改了p的${propName}属性,准备更新界面`)
return Reflect.set(target,propName,value)
},
//删除
deleteProperty(target,propName){
console.log(`删除了p的${propName}属性,准备更新界面`)
return Reflect.deleteProperty(target,propName)
}
})
</script>
</html>
2、proxy(代理)
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
被 Proxy 代理虚拟化的对象。它常被作为代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。
Proxy第一个参数是源数据。第二个参数是配置
3、Reffect(反射)
定义一个对象obj,obj下面有a,两个属性。一般我们要读取a属性,会用obj.a来实现。其实还有另外一种方式。就是Reflect。Reflect.get(obj,'a')
Reflect是一个组合的对象,它提供了阻止 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。
在reffect身上,就有defineProperty()这个方法
3、参数
target:
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler:
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
三、总结
在Vue2中,数据响应式主要借助Object.defineProperty()来实现,存在的缺陷是无法操作数据的增加和删除;
在Vue3中,数据响应式主要借助proxy和Reffect配合实现,可以做到实现数据的增删改查。