猿创征文 | 《深入浅出Vue.js》打卡Day2

第3章 Array的变化侦测

Object的侦测方法与Array的不同,Object是通过getter/setter的实现方式,而Array是通过原型上的方法来改变数组的内容。

一、如何追踪变化

Obejct的变化是靠setter来追踪的,只要一个数据发生了变化,一定会触发setter。

Array通过定义一个拦截器覆盖Array.prototype。之后,每当使用Array原型上的方法操作数组时,其实执行的都是拦截器中提供的方法。
在这里插入图片描述

拦截器

拦截器其实就是一个和Array.prototype一样的Object,里面包含的属性一模一样,只不过这个Object中某些可以改变数组自身内容的方法是我们处理过的

Array原型中可以改变数组自身内容的方法有7个,分别是push、pop、shift、unshift、splice、sort、reverse

有了拦截器之后,想要让它生效,就需要使用它去覆盖Array.prototype。但是我们又不能直接覆盖,因为这样会污染全局的Array,这并不是我们希望看到的结果,我们希望拦截操作只针对那些被侦测了变化的数据生效。也就是说希望拦截器只覆盖那些响应式数据的原型而将一个数据转换成响应式的,需要通过Observer,所以我们只需要在Observer中使用拦截器覆盖那些即将转换成响应式Array类型数据的原型。做法就是 将拦截器(加工后具备拦截功能的arrayMethods)赋值给value.__proto__,通过__proto__可以很巧妙地实现覆盖value原型的功能

// 我们平时有看到这样代码
arr.__proto__ = Array.prototype; 
// 这是不是就可以认为覆盖了Array原型身上的功能,arr也可以使用Array原型上的功能 (不知道说的对不对)

在这里插入图片描述

虽然绝大多数浏览器都支持这种非标准的属性来访问原型,但是并不是所有的浏览器都支持!因此,我们需要处理不能使用__proto__的情况——Vue直接将拦截器arrayMethods身上的这些方法设置到被侦测的数组上。
在这里插入图片描述

我们已经有了拦截器,当数据发生变化,被拦截器拦截,那之后我们通知谁呢?前面Object时是触发setter之后,是通知Dep中的依赖(Watcher),但是在Array中依赖是怎么收集呢?收集之后又通知谁呢?
简单回顾下Object是如何收集依赖?——是在definReactive中的getter里使用Dep收集的,每个key都会有一个对应的Dep列表来存储依赖。简单的说在getter中收集依赖,依赖存储在Dep里。

其实数组也是在getter中收集依赖,在拦截器中触发依赖。但这个getter收集到的依赖我们该保存到哪里呢,这个就很关键?它必须getter和拦截器都能够访问到。
所以我们把依赖保存到Observer实例上的dep中,是因为在getter中可以访问到Observer实例,同时在Array拦截器中也可以访问到Observer实例。

当侦测到数据发送变化时,会向依赖发送通知。此时,首先要能访问到依赖——通过数组__ob__属性拿到Observe实例,然后就可以拿到__ob__上的dep了。拿到dep属性之后,通过ob.dep.notify()去通知依赖(Watcher)数据发生了改变。

__ob__ 的作用不仅仅是为了在拦截器中访问Observer实例这么简单,还可以用来标记当前value是否已经被Observer转换成响应式数据。也就是说,被侦测了变化的数据身上都会有一个__ob__属性来表示它们是响应式的。如果value是响应式的,则直接返回__ob__;如果不是响应式的,则使用 new Observer来将数据转换成响应式数据。

侦测新增元素的变化

Observer类不光能处理Object类型的数据,还可以处理Array类型的数据。
如果数组有新增的数据,我们需要把新增的内容转换为响应式来侦测变化,否则就会出现修改数据时无法触发消息等问题。
实现步骤
1、我们需要在拦截器中对数组方法的类型进行判断。如果操作数组的方法是push、unshift和splice(可以新增数组元素的方式),则把参数中新增的元素拿过来,暂存在inserted中,接下来,我们要使用Observer把inserted中的元素转换成响应式的。
2、使用ob.observerArray来侦测这些新增元素的变化

二、关于Array的问题

Array的变化侦测是通过拦截原型的方式实现的。但是有些数组操作Vue.js是拦截不到的。例如:
1、修改数组中第一个元素的值,无法侦测到数组的变化;
2、清除数组操作也无法侦测到数组的变化。

三、总结

Array追踪变化的方式和Object不一样,我们是通过创建拦截器去覆盖数组原型的方式来追踪变化。

第4章 变化侦测相关的PAI实现原理

  1. vm.$watch 用于观察一个表达式或computed函数在vue.js实例上的变化
  2. vm.$set 这个方法主要用来避开Vue.js不能侦测属性被添加的限制
  3. vm.$delete 删除数据中的某个属性

如有写的不对的地方,欢迎来讨论
脚踏实地,一步一步来!!!

在这里插入图片描述

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*neverGiveUp*

你的鼓励是我最大的动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值