一、前言
距离 Vue3
出来了已经有一段时间了, 最近呢重温了一下Vue3的响应式方案,以及ref reactive的区别,相信你看完本文,也能对 Vue3 响应式的了解有所提高
在看源码的过程中,时常会感到框架的设计之美,看起来也会感到赏心悦目, 这也是能坚持把源码看下去的动力
二、新的方案
1. 缘由
- 已知在 Vue2 中, 响应式原理一直是采用
Object.defineProperty
来进行,那这样做有什么权限呢? 下面一一道来* 这个API, 只能拦截get
/set
的属性* 如对象新增
或者删除
了属性,则无法监听到改变* 对于数组,若使用数组的原生方法
改变数组元素的时候 也无法监听到改变 - 所以呢在Vue3中采用了
Proxy
和Reflect
搭配来代理数据2. Proxy 和 Reflect
1) Proxy
既然Vue3中响应式数据是基于 Proxy 实现的,那么什么是Proxy呢?
使用Proxy可以创建一个代理对象,它可以实现对 对象数据 的 代理
, 所以它 无法对非对象值进行代理
,也就是为什么Vue3中对于非对象值要使用 ref
来进行响应式的原因 (后面讲解ref的时候再细说)
- 代理是指 允许我们拦截并重新定义对一个对象的基本操作。 例如: 拦截读取、 修改等操作.
const obj = {}
const newP = new Proxy(obj, { // 拦截读取get(){/*...*/ },// 拦截设置属性操作set(){/*...*/ }
})
2) Reflect
说完了Proxy, 接下来我们来说说 Reflect
通过观察 MDN 官网可以发现, Reflect的方法 和 Proxy的拦截器方法 名字基本一致
那就出现了一个问题,我们为什么要用 Reflect 呢?
![](https://i-blog.csdnimg.cn/blog_migrate/b30ce849904ea102e5aea79114169dc5.png)
主要还是它的第三个参数,你可以理解为函数调用过程中的this
,我们来看看它配合 Proxy 具体的用途吧
const obj = {foo: 1,// obj 中有一个 getter属性 通过this获取foo的值get getFoo() { return this.foo; }
};
const newP = new Proxy(obj,{// 拦截读取get(target, key) {console.log('读取', key); // 注意这里目前没有使用 Reflectreturn target[key];},// 拦截设置属性操作set(target, key, newVal) {console.log('修改', key);target[key] = newVal}})
obj.foo++
console.log(newP.getFoo);
执行上面代码你会发现, 在 Proxy 中 get 拦截的中,只会触发对 getFoo 属性进行读取的拦截, 而无法触发在 getFoo 里面对 this.foo
进行读取的拦截!
问题就出现在 getFoo 这个getter里, 这里面的 this 在我们
未使用 Reflect
的时候指向它的原始对象
,所以我们才无法通过Proxy 拦截到属性读取
只需修改一下上面代码中 Proxy 里面的 get 拦截