Vue3 的响应式和以前有什么区别,Proxy 无敌?
前言
大家都知道,Vue2里的响应式其实有点像是一个半完全体,对于对象上新增的属性无能为力,对于数组则需要拦截它的原型方法来实现响应式。
举个例子:
letvm=newVue({ data(){ return{ a:1 } } }) //❌oops,没反应! vm.b=2
letvm=newVue({ data(){ return{ a:1 } }, watch:{ b(){ console.log('change!!') } } }) //❌oops,没反应! vm.b=2
这种时候,Vue提供了一个api:this.$set,来使得新增的属性也拥有响应式的效果。
但是对于很多新手来说,很多时候需要小心翼翼的去判断到底什么情况下需要用$set,什么时候可以直接触发响应式。
总之,在Vue3中,这些都将成为过去。本篇文章会带你仔细讲解,proxy到底会给Vue3带来怎么样的便利。并且会从源码级别,告诉你这些都是如何实现的。
响应式仓库
Vue3不同于Vue2也体现在源码结构上,Vue3把耦合性比较低的包分散在packages目录下单独发布成npm包。这也是目前很流行的一种大型项目管理方式Monorepo。
其中负责响应式部分的仓库就是@vue/rectivity,它不涉及Vue的其他的任何部分,是非常非常「正交」的一种实现方式。
甚至可以轻松的集成进React。
这也使得本篇的分析可以更加聚焦的分析这一个仓库,排除其他无关部分。
区别
Proxy和Object.defineProperty的使用方法看似很相似,其实Proxy是在「更高维度」上去拦截属性的修改的,怎么理解呢?
Vue2中,对于给定的data,如{count:1},是需要根据具体的key也就是count,去对「修改data.count」和「读取data.count」进行拦截,也就是
Object.defineProperty(data,'count',{ get(){}, set(){}, })
必须预先知道要拦截的key是什么,这也就是为什么Vue2里对于对象上的新增属性无能为力。
而Vue3所使用的Proxy,则是这样拦截的:
newProxy(data,{ get(key){}, set(key,value){}, })
可以看到,根本不需要关心具体的key,它去拦截的是「修改data上的任意key」和「读取data上的任意key」。
所以,不管是已有的key 还是新增的key,都逃不过它的魔爪。
但是Proxy更加强大的地方还在于Proxy除了get和set,还可以拦截更多的操作符。
简单的例子