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)
}
})










