Appearance
vue3响应系统
- 读《vue.js的设计与实现》 霍春阳
Vue.js 3 采用 Proxy 实现响应式数据, 取代 vue2中的 Object.defineProperty
1. 响应式数据与副作用函数
副作用函数指的是会产生副作用的函数
js
const obj = {
text: 'hello vue'
}
const effect = () => {
document.body.innerText = obj.text
}effect 函数的执行会直接或间接影响其他函数的执行,这时我们说 effect 函数产生了副作用。副作用很容易产生,例如一个函数修改了全局变量,这其实也是一个副作用,如上面的代码所示
响应式数据
js
obj.text = 'hello vue3'这句代码修改了字段 obj.text 的值,我们希望当值变化后,副作用函数自动重新执行,如果能实现这个目标,那么对象 obj 就是响应式数据
那么如何让数据,变成响应式数据?
vue2 使用 Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
Object.defineProperty(obj, prop, descriptor)
- obj: 目标对象
- prop: 属性名(字符串或Symbol)
- descriptor: 属性描述符对象,包含以下可选键值:
- value: 属性值
- writable: 是否可写
- enumerable: 是否可枚举
- configurable: 是否可配置
- get: getter函数,用于获取属性值
- set: setter函数,用于设置属性值
通过get/set拦截属性访问
Vue2 的响应式原理即基于此:
js
const obj1 = {}
Object.defineProperty(obj1, 'name', {
value: '张三',
get() {
return this.value + '??'
},
set(newVal) {
this.value = newVal
document.body.innerText = this.value
},
})
console.log(obj1.name) //张三??
obj1.name = '李四'
console.log(obj1.name) //李四??Vue.js 3 采用 Proxy
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
const p = new Proxy(target, handler)
- target: 目标对象
- handler: 一个对象,其属性是当执行一个操作时定义代理的行为的函数
- get
- set
基础使用
js
//定义一个需要代理的对象
let person = {
age: 0,
name: '张三'
}
// 定义代理
let proxyObj = new Proxy(person, {
/**
* obj 目标对象
* key 属性名
*/
get(obj, key) {
console.log('触发了get')
// 如果对象里有这个属性,就返回属性值,如果没有,就返回默认值66
return key in obj ? obj[key] : '无此值'
},
/**
* obj 目标对象
* key 属性名
* val 属性值
*/
set(obj, key, val) {
console.log('触发了set')
obj[key] = val
return true
}
})
console.log(proxyObj.name) //张三
console.log(proxyObj.age) //0
console.log(proxyObj.test) //无此值可以看出,Proxy代理的是整个对象,而不是对象的某个特定属性,不需要我们通过遍历来逐个进行数据绑定。