vue3中使用proxy替代defineProperty的原因是什么(defineproperty,proxy,vue3,开发技术)

时间:2024-05-06 08:13:02 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    vue3%E4%B8%AD%E4%BD%BF%E7%94%A8proxy%E6%9B%BF%E4%BB%A3defineProperty%E7%9A%84%E5%8E%9F%E5%9B%A0%E6%98%AF%E4%BB%80%E4%B9%88

用最简单的讲法就是:初始化数据生成了页面,直接修改源数据触发更新,页面重新渲染

关注vue的人都知道,vue3里面使用了proxy替换了defineProperty,

在使用vue2的时候,我们经常会碰到一个问题,添加新的对象属性obj.a = 1会无法被vue2劫持,必须使用vue2提供的$set方法来进行更新

这个的原因想必大家也都清楚,因为defineProperty只能对当前对象的其中一个属性进行劫持

当我们给a对象新增一个属性的时候,当前新增的属性并没有被defineProperty劫持,虽然在对应的对象上依旧成功的生成了一个新的属性,但是我们知道,vue2是通过defineProperty的setter与getter进行数据劫持的,既然新增的数据并没有被劫持,所以无论怎么更新,页面依旧不会重新渲染

而在vue3中,使用proxy来进行数据代理就完全没有这个顾虑了

proxy对于数据的代理,是能够响应新增的属性,当新增一个属性的时候,可以响应到get中,对当前对象进行代理

vue3是如何通过proxy代理的

首先可以看下vue3新增的几个主要apiref, reactive, effect,computed

vue3中对vue2的兼容处理也是使用了reactive,即instance.data = reactive(data),将整个data属性使用reactive进行代理

我们知道,vue2中的data就是使用Object.definePerproty进行数据劫持的, 那么在reactive中,他是如何使用proxy进行数据代理的,来兼容老的书写方式与新的compositionApi

ps: 由于在reactive里面也只是通过proxy对传入的数据校验和代理,最主要的还是set和get,所以我们还是直接上垒吧,毕竟心急吃得了热豆腐

get

可以分析一下,vue2也好,vue3也罢,针对于数据的获取所做的事情主要内容不会有什么区别

但是,针对于vue3使用proxy的特性,在这边额外做了一部分的兼容

effect依赖采集

vue除去正常的data的数据代理以外,还有对应的computed和watch,而在vue3中直接使用了watchEffect和computed方法能够直接生成对应的内容

他们的数据更新和依赖处理都是依托于当前data数据上的get进行依赖的收集

掐头去尾的来看最核心的代码

单纯从这段代码出发去解读的话,可能会有一定的困难,换个角度,从vue3的整体使用情况出发,返回来解读这段代码

首先,在effect中使用了前面通过reactive定义的b,从表面现象出发的话,我们能知道,当b.c发生变化的时候,a也会同步发生变化

这个变化的原因就是上述源码中的activeEffect,当创建的effect被调用的时候,会将activeEffect设置为自身,并执行相应的回调函数,函数的调用会触发到各自使用到的数据的getter,将对应的effect依赖注入到每个使用的数据上

至于为什么会设置这么复杂的一个属性的依赖获取,是因为使用proxy的原因,proxy代理了一整个对象,就不能像vue2使用Obect.defineProperty直接在getter里面就当前的字段进行一个依赖绑定,所以在vue3中是直接将整个对象作为一个Map,每个Map的key都是对应的属性,而value则是所有依赖当前属性的对象

set

同get,依旧保持着原先的思路跟模式

在vue3中,还是有部分区别的,毕竟是单独拉出去的一个库

所以,如果想当前的数据直接可以更新的话, 可以优先使用effect,他会比watchEffect的更新速度快一点,劣势是可能很多东西得自己写 =,=

至于怎么实现的其实就很简单了

但是里面有一个特殊的处理,针对于数组的length属性,这个属性是有一定区别的,接下来具体讲讲在vue3中的数组操作

数组

在vue2中的,针对数组是多做了一层处理,代理了数组的基本方法,这是因为使用Object.defineProperty在数组上面天然存在劣势

具体原因在vue的文档中写的非常清楚了,这里就不详细叙述了

文档地址

而在vue3中使用proxy就完美的解决了这个问题,只是因为proxy能够监听数组的变化,做个测试

当我们代理了一个数组之后,直接调用push插入一个新的数据,能够明显的看到getter跟setter都会被调用两次,一次是调用的push方法,而另一次是数组的长度length,也就是说,proxy不仅仅会检测到我们当前调用的方法,还能够知道我们的数据长度是否发生了变化

看到这边,可能会有一个疑惑,push是对当前数组进行的操作,但是数组里面还有部分方法是会返回一个新的数组,proxy是否会对新生成的数组也进行代理,这里我们拿splice举个例子

从表现形式来看,proxy代理之后的数组只会对当前数组的内容进行监听,也就是调用splice之后新生成的数组的变化是不会被代理的

现在我们回过头来看下vue3的trigger方法,这个是vue在set完成之后触发的依赖更新,同样的掐个头去个尾,除去正常的执行以外,我们看下针对数组做的优化

由于我们知道, 在一次操作数组的时候会进行多次的set,那么如果每次set都要去更新依赖的话,会造成性能上的浪费,所以在vue3里面只有在set length的时候才会去调用add方法,然后统一执行所有的更新

结语

不得不说,proxy比defineProperty强大了太多,不仅解决了vue的历史难题,让vue的体验更上了一层,更是去除了不少因为defineProperty而必须要的方法,精简了vue的包大小

虽然proxy的兼容性是比defineProperty差不少,但是在vue里面基本已经抛弃了IE,所以如果你的项目需要在ie下运行的话,那就请放弃vue这个选择,使用低版本的react的吧,哈哈哈哈哈哈

在移动端里面基本上就是没有这种版本的限制,实在是版本低不能使用proxy的话,相信去找找polyfill是能够找到的

本文:vue3中使用proxy替代defineProperty的原因是什么的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:php进行string替换的方法下一篇:

16 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18