Vue3的底层实现-响应式数据的Proxy
介绍
相对于Vue2的defineProperty的实现,Vue3采用Proxy的实现。defineProperty为静态方法因此无法监听新增属性/删除属性,并且无法直接监听数组。
主要通过Reflect的四个方法操作语言内部的属性,Reflect的原型就是Object。
Reflect.get(目标对象,属性名,上下文对象) – 读取对象属性
Reflect.set(目标属性,属性名,属性值,上下文对象)-- 设置对象属性
Reflect.deleteProperty(目标对象,属性名)-- 删除对象属性
Reflect.ownKeys(目标对象)-- 返回由目标对象自身的属性(只处理本身-非原型的属性)组成的数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| function reactive(target) { if (typeof target !== 'object' || typeof target == null) { return target } const proxyConf = { ~ get(targe, key, receiver) { const ownKeys = Reflect.ownKeys(target) if(ownKeys.includes(key)) { console.log('get', key) } const result = Reflect.get(target, key, receiver) return reactive(result) },
set(target, key, val, receiver) { if(val === target[key]) { return true; } const ownKeys = Reflect.ownKeys(target) if(ownKeys.includes(key)) { console.log('set 已有的属性', key) } else { console.log('set 新增的属性', key) } const result = Reflect.set(target, key, val, receiver) console.log('set', key, val) return result },
deleteProperty(target, key) { const result = Reflect.deleteProperty(target, key) console.log('deleteProperty', key) return result } } const observed = new Proxy(target, proxyConf) return observed; }
|
例如获取对象 a 中属性 d 的值:
1 2 3 4 5 6 7 8 9
| const a = { b: { c: { d: 'proxy' } } } let ref_a = reactive(a) console.log(ref_a.b.c.d)
|
get 方法总共会调用3次,即进行三次递归,直到下一次 get 的不是对象或者数组。
与definePropety的区别是,proxy只有我们读取到对象深层次的属性时,才会触发递归,而definePropety的深度监听会一次性监听所有数据。