vue存json数组_从源码中学Vue(四)——看清数据劫持的本质

本文探讨了Vue中数据劫持的概念,通过源码分析了如何利用`Object.defineProperty`进行数据监听。文章详细介绍了`Observer`类的工作原理,以及如何在数据变化时触发更新。在数据对象的深层结构中,Vue会递归地创建响应式属性,确保所有子对象的变化都能被捕捉到。
摘要由CSDN通过智能技术生成

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

6cc9ce2037d4039410ea07c207441bb1.png

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

本章目标

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

Object.defineProperty

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

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

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

8beb3c865d8fc3de63090e50fc0d7a74.gif

一个对json的简单存取操作

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

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

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

1e9716ff6fb1182deca95c5ebabc9b2a.gif

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

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

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

Vue是如何做数据劫持的

源码路径node_modulesvuesrccoreobserverindex.js

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

37519ce1c4dd34f6ec0aabe5512530b0.png

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

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

eecdde181f59fe1c888bf654faab4b1e.png

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

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

124f581137cd2b024e2bf29cbe7e0fe3.png

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

4cbfdd94b418e459d0f552b6f525d883.png

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

5ac2ddc38b52166c27ad78b3987f71a9.png

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

0141f84bc9f6b2dd882911d1ec237387.png

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

首先我们来看这段源码

fc2f539f5681500447c3a001d7d62aea.png

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

来看一个示例

d0f2bef2c5bb63e55d37df0e08a83ad7.gif

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

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

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

再往下看

b61b2dd78d7216d5b4a3f81f4116d4f2.png

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

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

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

8152cd1d5e286687bea6c2565593ce5c.png

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

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

3cef16c6b0ff5253f5f375ccfccf16bf.gif

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

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

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

0c7f3b2de0069a7bab75ff6409eee26e.png

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

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

总结:

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

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

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值