Vue3 的响应式数据实现原理,使用Proxy替换Object.defineProperty;新增Composition API,更好的逻辑复用和代码组织
Vue2的响应式
-
实现原理:
- 对象类型:通过 Object.defineProperty() 对属性的读取、修改进行拦截(数据劫持)。
- 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
-
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
-
实现如下:
<script type="text/javascript">
// 源数据
let person = {
age: 12,
name: 悟空
}
/*
模拟Vue2的响应原理
*/
let p = {}
Object.defineProperty(p, 'name', {
// configurable为true,就可以删除属性了
// configurable: true,
get() {
console.log('有人读取了name属性')
return person.name
},
set(value) {
console.log('有人修改了name属性')
person.name = value
}
})
Object.defineProperty(p, 'age', {
get() {
console.log('有人读取了age属性')
return person.age
},
set(value) {
console.log('有人修改了age属性')
person.age = value
}
})
</script>
Vue3的响应式
- 实现原理:
- 通过 Proxy(代理): 是window的构建函数,拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过 Reflect(反射): 对源对象的属性进行操作。
- 实现如下:
<script type="text/javascript">
let person = {
age: 12,
name: 'bajie'
}
const p = new Proxy(person, {
// 读取属性
get(target, propName) {
console.log('读取了属性')
return Reflect.get(target, propName)
},
// 修改属性
set(target, propName, value) {
console.log('修改、增加了属性')
Reflect.set(target, propName, value)
},
// 删除属性
deleteProperty(target, propName) {
console.log('删除了属性')
Reflect.deleteProperty(target, propName)
}
})
<script type="text/javascript">