vue => 什么意思_从源码中学Vue(四)——看清数据劫持的本质

欢迎来到我的《从源码中学Vue》专题系列文章,更多精彩内容持续更新中,欢迎关注 :)

d6fc430d683b2672b1bcf3f0e7c11dd3.png

要说Vue的亮点有哪些,那么它的数据劫持绝对算是一大亮点。那么接下来我将通过源码去分析在Vue中的数据劫持究竟是怎么实现的

本章目标

  1. ES5中的Object.defineProperty基本用法
  2. Vue是如何做数据劫持的

Object.defineProperty

稍微对Vue数据劫持原理有了解的都知道,它就是通过Object.defineProperty这个ES5提供的Api来实现的。

那么在阅读源码之前,很有必要先去了解一下Object.defineProperty它的基本用法。

一般来说,我们去操作JS对象的时候,可以去获取对象的值,也可以去设置对象的值,像这样

4b990b0945624496f9c35e4f3ea00bce.gif

一个对json的简单存取操作

这里有一个弊端就是,我们不管是在存数据或者是取数据的时候,仅仅是一个很单一的操作,这各过程中我们无法去做一些我们自定义的事情。

所以在ES5中为我们提供了Object.defineProperty来解决这个问题。

Object.defineProperty(obj,key,描述信息);这里的描述信息非常重要,我们来看最基础的用法。

beb154f6cd05bb64bc35e376f096f624.gif

可以看到,我们将对象通过Object.defineProperty来定义后,可以通过get和set方法去劫持Object对象属性发生变化。

这里面我们就可以做很多事情了。比如在数据改变后,去更新dom。

好了,接下来我们继续去看下Vue针对数据劫持的源码实现吧~

Vue是如何做数据劫持的

源码路径node_modulesvuesrccoreobserverindex.js

Observer类,在Vue中的作用就是观察类,专门用来监测Vue实例$data上的数据的变化。

05754ca8f7845d64653bebee3857f446.png

在构造方法中,Vue优先判断了参数value的类型是否为数组,那么我们先就看下一般来说,Vue中在调用Observer的时候这个value到底传入的实参到底是什么?

我们进入到node_modulesvuesrccoreinstancestate.js中,找到一个叫initData的方法,这个方法处理Vue 实例上的data对象的,在该方法的最后面我们可以看到有一个observe方法。

17bd50383c4ecbba4ee03c283a1affc4.png

这个方法传入的实参就是Vue实例上的$options.$data对象。

这个observe方法的定义的意思就是专门实例化Observer类,它的源码也在node_modulesvuesrccoreobserverindex.js中,

796339e5327df7f8d55f2a49b9444d80.png

再回到我们的Observer类的定义当中,我们现在知道了,构造方法的每 个参数value,我们实际传入的是Vue实例下的data对象,也就是value是一个对象。

ff597067a2f7e978bcffcdf59aaf5d23.png

所以在构造方法中会走else里面的判断,即 walk方法被调用了。我们再去看看walk方法做了什么?

526844955649d932032e2bae73602717.png

很简单,这个方法的作用就是将我们的data上每一条数据都定义了响应式。再来看defineReactive方法的具体实现。

58949ad326ef48f53dd2ec8f20f8b8ca.png

大概看一下,它就是将我们的data数据中的每一个key值都通过Object.defineProperty来定义了。

首先我们来看这段源码

727e6c5623cabbd1eb092f6694c93336.png

Object.getOwnPropertyDescriptor这个方法是用来获取我们通过 Object.defineProperty设置的描述。

来看一个示例

f736879f994683fa16267b4bc07d59b3.gif

也就是说我们通过const property = Object.getOwnPropertyDescriptor(obj, key)获取到Object.defineProperty第三个参数的配置。

 if (property && property.configurable === false) { return }

如果说不允许配置,那么后面的响应式也没意义,所以这里做了return 终止。

再往下看

efa656745e433df5776fc9c1aea984c5.png

childOb,从字面的上理解就是子观察对象。shallow意思为浅的,我们在walk方法中调用defineReactive方法的时候,没有传入shallow对应的参数,所以他返回false.

也就是说:childOb也接着会继续实例化Observer类,继续观察对象中的子对象。

应对的情况就是我们的data对象中的key对应的值也是一个对象。

7b7a9f6609444cc213c14fe0763a0433.png

这个时候,我们不仅要观察formObj对象,里面的对象我们需要继续观察。

难道Object.defineProperty不会主动去观察吗?我们来举个例子就知道了。

8d6a8b7fae460d5c3811d52aad4507c8.gif

可以看到,我们重新在修改了obj.a为一个对象的时候,这个对象并没有设置get和set,

这也是Object.defineProperty的一个缺陷吧。

我们再去看看set方法中的实现

76e3b0955816cb4e011d0afb7b37d6de.png

咦?这里怎么会又有一个childOb 呢??

我来解释一下:比如我们在data对象下定义一个formObj为1,我们通过vm.formObj = {name:123}了,这时候我们将formObj本来是一个普通的数字改成了一个对象值,所以这个时候我们需要继续去观察了。

总结:

  1. Object.defineProperty基本用法
  2. 我们通过Object.defineProperty内部通过get和set来劫持数据

这里是畅哥聊技术 《从源码中学Vue》系列文章,更多精彩内容持续更新中,敬请期待。

未完待续。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值