Proxy
响应式原理
1.Vue2
的响应式
- 实现原理:
- 对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持) - 数组类型:通过重写更新数组的一系列方法来实现拦截,(对数组的变更方法进行了包裹)
Object.defineProperty(data, 'count', { get(){}, set(){} })
- 对象类型:通过
- 存在问题:
- 新增属性、删除属性,界面不会更新
解决方式:
this.$set()\Vue.set()
,this.$delete()\Vue.delete()
- 直接通过下标修改数组,界面不会更新
解决方式:
this.$set()\Vue.set()
,Array.splice(0,1,‘demo’)
2. Vue3
的响应式(Proxy
)
- 实现原理:
- 通过
Proxy(代理)
:拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等 - 通过
Reflect(反射)
:对被代理的对象的属性进行操作 MDN
文档中描述的Proxy
和Reflect
:Proxy
:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ProxyReflect
:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
- 通过
- 示例
Proxy
<script>
let data = {
name: '张三',
age: 19
}
// 模拟Vue3响应式
const p = new Proxy(data, {
// 接收参数 target:传入对象, propName: 读取到的具体属性名
// 有人读取了某个属性
get(target, propName){
console.log(`有人读取了p身上的${propName}属性`,target, propName)
return target[propName]
},
// 有人修改了p的某个属性、或新增某个属性
set(target, propName, value){
console.log(`有人修改或新增了p身上的${propName}属性`)
target[propName] = value
},
// 有人删除某个属性
deleteProperty(target, propName){
console.log(`有人删除了p身上的${propName}属性`)
return delete target[propName]
}
})
</script>
效果图:
- 示例
Reflect
:
Reflect.get(target, propertyKey[, receiver])
获取对象身上某个属性的值,类似于target[name]
。Reflect.set(target, propertyKey, value[, receiver])
将值分配给属性的函数。返回一个Boolean
,如果更新成功,则返回true。Reflect.deleteProperty(target, propertyKey)
作为函数的delete
操作符,相当于执行delete target[name]
。Reflect.defineProperty(target, propertyKey, attributes)
和Object.defineProperty()
类似。如果设置成功就会返回 true
举个例子:
<script>
let data = {
name: '小明'
}
// Object.defineProperty操作, 重复定义会报错,不能继续往下执行,检验错误写在try...catch中
// Object.defineProperty(data, 'age',{
// get(){
// return 19
// }
// })
// Object.defineProperty(data, 'age',{
// get(){
// return 20
// }
// })
// Reflect操作,直接返回Boolean,不会打断运行
let x1 = Reflect.defineProperty(data, 'age',{
get(){
return 19
}
})
console.log(x1)
let x2 = Reflect.defineProperty(data, 'age',{
get(){
return 20
}
})
console.log(x2)
if(x1){
console.log('设置成功')
} else{
console.log('设置失败')
}
console.log('@@@')
</script>
3.所以模拟Proxy
响应:
// 模拟Vue3响应式
const p = new Proxy(data, {
// 接收参数 target:传入对象, propName: 读取到的具体属性名
// 有人读取了某个属性
get(target, propName){
console.log(`有人读取了p身上的${propName}属性`,target, propName)
// return target[propName]
return Reflect.get(target, propName)
},
// 有人修改了p的某个属性、或新增某个属性
set(target, propName, value){
console.log(`有人修改或新增了p身上的${propName}属性`)
// target[propName] = value
return Reflect.set(target, propName, value)
},
// 有人删除某个属性
deleteProperty(target, propName){
console.log(`有人删除了p身上的${propName}属性`)
// return delete target[propName]
return Reflect.deleteProperty(target, propName)
}
})