Vue3中最重大的更新之一就是响应式模块reactivity的重写。主要的修改就是Proxy替换defineProperty`实现响应式。此变化主要是从性能方面考量。
思路
- 属性拦截的几种方式
- defineProperty的问题
- Proxy的优点
- 其他考量
JS中做属性拦截常见的方式有三:defineProperty,getter/setters 和Proxies.
Vue2中使用
defineProperty的原因是,2013年时只能用这种方式。由于该API存在一些局限性,比如对于数组的拦截有问题,为此vue需要专门为数组响应式做一套实现。另外不能拦截那些新增、删除属性;最后defineProperty方案在初始化时需要深度递归遍历待处理的对象才能对它进行完全拦截,明显增加了初始化的时间。
以上两点在
Proxy出现之后迎刃而解,不仅可以对数组实现拦截,还能对Map、Set实现拦截;另外Proxy的拦截也是懒处理行为,如果用户没有访问嵌套对象,那么也不会实施拦截,这就让初始化的速度和内存占用都改 善了。
当然
Proxy是有兼容性问题的,IE完全不支持,所以如果需要IE兼容就不合适
知其所以然
Proxy属性拦截的原理:利用get、set、deleteProperty这三个trap实现拦截
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {},
set(target, key, val) {},
deleteProperty(target, key) {},
})
}
Object.defineProperty属性拦截原理:利用get、set这两个trap实现拦截
function defineReactive(obj, key, val) {
Object.defineReactive(obj, key, {
get(key) {},
set(key, val) {},
})
}