vue2 的响应式
使用 Object 构造函数上 defineProperty() 实现
存在的问题 :
对象新增的属性没有响应式数组部分操作没有响应式
解决办法
1、 用
Vue.set进行添加或修改,Vue.delete进行删除。
2、使用数组的一些方法对数组操作 (如push(),splice(),pop(),shift(),unshift(),sort(),reverse()
3、使用vue实例对象上的$set进行添加或修改,$delete进行删除。
4、使用vue实例对象上的$nextTick进行页面更新
实现响应式的原理
对象类型:通过Object.defineProperty()对属性的读取,修改进行拦截(数据劫持)数组类型:通过重写更新数组的方法来实现拦截(对数组的变更方法进行包裹)
Object.defineProperty参数说明
Object.defineProperty("对象", "属性", {
value: 0, // 属性值
enumerable: true, // 属性是否可被枚举,默认 false
writable: true, // 属性是否可被修改,默认 false
configurable: true, // 属性是否可被删除,默认 false
get() {}, // 获取属性值时调用,此函数需返回属性的属性值
set(value) {}, // 修改属性值时调用,value为修改后的值
})
vue2 实现响应式
// 定义源对象
let person = {
name:"张三",
age:18
}
// 定义代理对象
let obj = {}
Object.defineProperty(obj ,"name",{
get(){
return person.name
},
set(val){
console.log(val)
person.name = val +"aaa"
}
})
console.log(obj .name);
obj.name = "李四"
// 更改obj.name的值,会触发set方法
console.log(person) // name = "李四aaa" 因为set方法return时是val+"aaa"
vue3 的响应式
使用 window 上的内置构造函数 Proxy 实现。
实现原理
Proxy(代理):拦截对象中任意属性的变化,包括属性值的读取、修改,以及属性的添加和删除Reflect(反射):对源对象的数学进行操作。
// 定义源对象
let person = {
name:"zhangsan",
age:18
}
// 定义代理对象
let p = new Proxy(person,{
// target:源对象,key:源对象的属性名,val:源对象的属性值,receiver:代理对象,一般不用,可以不写,默认是代理对象,也就是p,如果写了,就是写的值,比如写了p1,那么就是p1,如果不写,就是p
get(target,key){
return target[key]
},
// val:更改后的值,也就是p.name = "lisi"中的lisi,也就是set方法中的val,也就是p.name = val中的val
set(target,key,val){
console.log(val)
target[key] = val +"aaa"
},
deleteProperty(target,key){
console.log(target,key)
return delete target[key]
}
})
console.log(p);
但是上述代码依然存在问题。例如:
const p1 = Object.defineProperty(person,"name",{
get(){
return "李四"
}
})
// 在这里会出现异常
const p2 = Object.defineProperty(person,"name",{
get(){
return "王五"
}
})
console.log(person)
在上述代码中,因为我们重复的对 person 的name属性进行了操作,就会出现异常,导致单线程挂掉,如果需要解决出现的问题,需要用try...catch 对异常进行捕获
同时,我们也可以用 Reflect 处理这种问题
Relect 是 window 上的内置构造函数,与 Object 不同的是,Reflect 会返回一个布尔值,可以更灵活地捕捉到异常,判断操作是否成功,从而进一步对错误进行抛出
实现响应式可以优化为:
let p = new Proxy(person,{
get(target,key){
return Reflect.get(target,key)
},
set(target,key,val){
return Reflect.set(target,key,val)
},
deleteProperty(target,key){
return Reflect.deleteProperty(target,key)
}
})
Vue2通过Object.defineProperty实现响应式,对属性读取和修改进行拦截,但新增属性不响应。Vue3则使用Proxy能拦截对象任意属性变化,更全面。Vue2中可通过Vue.set等方法解决新增属性响应性问题,而Vue3的Proxy配合Reflect提供更灵活的异常处理。

被折叠的 条评论
为什么被折叠?



