持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
对比 Vue3 和 Vue2 ,有很多变化的地方,其中一个就是响应式的实现, Proxy 替代了 Object.defineProperty。
defineProperty 在前文中有介绍过它的原理以及手写方法: Vue进阶 | 实现一个Vue2响应式,那么是为什么 Vue3 使用了 Proxy ,而不再使用 Object.defineProperty 呢?
1、Object.defineProperty
defineProperty 是:数据劫持 + 发布者-订阅者 模式
通过Object.defineProperty()
来劫持各个属性的 setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
也就是,通过get
和set
这两个属性(属性的 getter 函数、属性的 setter 函数):
- 当访问该属性时,会调用get()
- 当属性值被修改时,会调用set()
并且在 Vue2 中,对象这种结构在添加新的属性或是进行删除操作,是无法劫持到的,视图不会自动更新,需要借助一些方法,比如:
- $set()
- this.$set(this.obj, key, value)
- Vue.set(this.obj, key, value)
- 展开运算符
- this.obj = {...this.obj}
- assign
- this.obj = Object.assign({}, this.obj, { newKey: newValue })
- this.$forceUpdate()(不推荐)
- 强制更新视图,执行后会触发updated生命周期,且仅影响本身和插槽内的子组件,而不是所有的子组件
但是这样对于数据层级较深的结构进行监听时,会对性能产生影响
2、Proxy
Proxy 会监听对象的所有操作,也可以直接监听到数组的变化
相较 Object.defineProperty():
- Proxy 直接劫持到整个对象,返回的是一个新对象,所以可以只操作新的对象,Object.defineProperty 只时遍历对象属性,直接进行修改
- Proxy 有多达 13 种拦截方法,如 apply、ownKeys、deleteProperty、has (Object.defineProperty 没有这些方法)
- Object.defineProperty 需要遍历所有的属性,监听所有的属性的变化,占用内存较大
实现形式对比
1、Object.defineProperty:
根据具体的 key 对 get 和 set 进行拦截
2、Proxy:
proxy 不关心具体的 key,拦截的是修改 data 上的任意 key 和读取 data 上的任意 key