![90f865ec7b729a4d5276636814eb8b2d.gif](https://i-blog.csdnimg.cn/blog_migrate/a6aac5faa7c2c478a3f66bf1d8455475.gif)
点击上方蓝色字关注我们~
前端之火永不熄灭,Vue该学的一点都不能少!
1
前言
我们以前实现过一个简单的响应式逻辑,但是比起 Vue 的实现那简直就是小孩子的玩具,
在Vue 中, 使用了observer, watcher,和 dep 三种对象来实现响应式。
而响应式的属性是具有嵌套特征的复杂对象。这里涉及到设计模式,递归与算法等,可谓是代码的技巧精华所在。2
响应式系统
Template
![025c2d5bbc3bc3099435f90937e8c4f0.png](https://i-blog.csdnimg.cn/blog_migrate/7572b423d41f3a9ca0285a331ce21863.png)
Script
![a2a57c4ccf793a252e285c418e2b338c.png](https://i-blog.csdnimg.cn/blog_migrate/8f07f863d393fa182646775518533e05.png)
在Vue中我们通过双大括号进行插值,我们都知道在Vue中声明的数据都是响应式。
什么是响应式?也就是说我们将页面中的数据进行改变的时候吗,视图会重新渲染,匹配到最新的值。也就是这个原因我们可以脱离页面,不用去操作DOM,只需要关心数据。
但是问题来了????
1.Vue是怎么知道数据改变的呢?
2.数据在改变的是时候是怎么通知哪些视图更新的呢?
3.数据在改变的时候,视图咋知道它什么时候更新呢
3
Object.defineProperty
我们在js中提供了Object.defineProperty,在Vue3.0没有出现之前,这个方法可以说是Vue的精髓,Vue3.0中借用了proxy实现了数据的双向绑定,由于Vue3.0现在还不够完善,我这里只来说Object.defineProperty。
使用 Object.defineProperty 可以为对象中的每一个属性,
设置 get 和 set 方法。
Object.defineProperty 可以为属性设置很多特性,例如 configurable,enumerable,但是现在不过多解释,重点只放在 get 和 set 。
get 值是一个函数,当属性被访问时,会触发 get 函数
set 值同样是一个函数,当属性被赋值时,会触发 set 函数
举个例子:
![bcc1c90f06ada8bee5d48a2b1d714105.png](https://i-blog.csdnimg.cn/blog_migrate/17ba74c83b96a4192bb4a479cc3b4374.png)
我们在读取obj.name的时候会执行get函数,控制台会执行get中的内容。
我们给设置obj.name=‘123’的时候会执行set函数,控制台会执行get函数中的内容。
这样我们第一个问题也就迎刃而解了。
Vue 是怎么知道数据改变的呢?
Vue 在 属性的 set 方法中做了手脚,因而当数据改变时,触发 属性的 set 方法,Vue 就能知道数据有改变。
4
依赖收集
简单地说
data 中的声明的每个属性,都拥有一个数组,保存着谁依赖(使用)了 它
举个例子:
![9369ae591698bf7dc0c8563fe78f4d9e.png](https://i-blog.csdnimg.cn/blog_migrate/ad95f416391bba0b878463032a060b1e.png)
然后我们在Ttape页面引用了name
![599ccc06b14772279c0475bf56515940.png](https://i-blog.csdnimg.cn/blog_migrate/7c605c65080fa344dc1688936892a43b.png)
此时name对页面Ttape产生了依赖。
为什么呢?
因为它知道谁依赖它之后,它就可以在发生改变的时候,通知 依赖它的页面,从而让页面完成更新。
实际上,会依赖 name 的地方,不只是页面,还会有 computed,watch.... 等等,但是这里我们全部使用页面一词替代。
这就是依赖收集,把 依赖了我(使用了我的东西),统统保存起来。
我按上面的例子,从Vue 内部打印一份数据供大家简单了解即可。
![5e77151d6bb20100f83c403ada2a7f4d.png](https://i-blog.csdnimg.cn/blog_migrate/24d79c48a301e706d7da2aaec7304727.png)
可以看到,name 属性,使用了 一个 dep 保存了 页面Ttape这个依赖,而保存的实际上是 页面Ttape的 Watcher。
简单说一下,watcher 是什么,每个 Vue 实例都会拥有一个专属的 watcher,可用于实例更新
总结一下
1.data 中每个声明的属性,都会有一个 专属的依赖收集器 subs
2.当页面使用到 某个属性时,页面的 watcher 就会被 放到 依赖收集器 subs 中数据是在什么时候进行收集依赖的呢?
答案是,ObjectdefineProperty - get
当页面 Ttape读取了 name 时,会触发 name 的 get 函数,此时,name 就会保存 页面Ttape 的 watcher 啦。
这便可以回答了我开篇的第二个问题,
数据在改变的是时候是怎么通知哪些视图更新的呢?恩,通知那些存在依赖收集器中的视图。5
依赖更新
依赖更新,就是通知所有的依赖进行更新。
每个属性都会保存有一个依赖收集器subs,
而这个依赖收集器,是用来在数据变化时,通知更新的。
数据是在什么时候进行依赖更新的呢?
答案是,Object.defineProperty - set
以上面的 Vue 实例 为例
当 name 改变的时候,name 会遍历自己的 依赖收集器 subs,逐个通知 watcher,让 watcher 完成更新。这里 name 会通知页面A,页面A重新读取新的 name ,然后完成渲染。
这便可以回答了我开篇的第三个问题
Vue 在数据改变时,视图怎么知道什么时候更新?
在数据变化触发 set 函数时,通知视图,视图开始更新。6
总结
1.Object.defineProperty - get ,用于依赖收集
2.Object.defineProperty - set,用于依赖更新
3.每个 data 声明的属性,都拥有一个的专属依赖收集器 subs
4.依赖收集器 subs 保存的依赖是 watcher
5.watcher 可用于进行视图更新
往期回顾
牢记!前端工作中遇到99%的工作,都不能靠跳槽解决
前端这道“常见又讨厌”的面试难题,要怎么答?
技术大佬都在用碎片时间学习Vue充电,你竟然还能坐得住?
前端大佬不懂虚拟DOM,那不好意思你快被pass了!
前端年度跳槽技术要求:不懂Vue千万别轻举妄动!!
·END·
极光学苑
带你飞向梦想的地方
微信号:极光训练营
谢谢你的“在看” ❤