Vue源码探秘之数据响应式原理笔记

238 阅读3分钟

Vue源码探秘之数据响应式原理笔记

第一节课

彻底弄懂Vue2的数据更新原理,手写相关实现代码,让相关知识不再处于“忽悠阶段”

从MVVM模式说

模板:<p>我{{age}}岁了</p>
数据变化:this.age++
数据变了,视图就会跟着变化
model<=>view

侵入式和非侵入式

  Vue数据变化      //属于非侵入式
  this.a++;    
  React数据变化     //属于侵入式
  this.setState({
  a:this.state.a+1;
  });
  小程序数据变化      //属于侵入式
  this.setData({
  a:this.data.a+1;
  )};

侵入式比如小程序实际上是在setState函数中书写一些语句去改变视图,setState不仅可以改变数据还可以改变视图;非侵入式改变a属性就可以改变视图,这是js赋予的功能,原因是Object.defineProperty()(被称为上帝的钥匙)用来做数据劫持/数据代理,不需要引用任何的包,也不需要任何的插件,从ie8开始兼容,利用js(JavaScript)引擎赋予的功能,检测对象属性的变化,仅有上帝的钥匙还不够,还需要设计一套精密的系统。

第二节课

学习Object.defineProperty()方法

Object.defineProperty()方法会直接在一个对象上定义一个新属性,
或者修改一个对象的现有属性,并返回此对象。

搭建环境

和虚拟DOM和diff算法搭建环境的方法一样

Object.defineProperty()可以设置一些额外的隐藏属性

可以使属性更加自由的被定义 图片.png 结果

图片.png

set()函数和get()函数

get()函数和value不能一起在Object.defineProperty()中定义

图片.png 上图表明相当于把a数据给劫持了,非侵入式 图片.png

图片.png

第三节课

defineReactive函数

setter函数仅接受参数赋值给该属性的新值,默认为undefined
getter函数的返回值将被作为该属性的值,默认为undefined

图片.png

图片.png

图片.png

    setter函数和getter函数需要变量周转才能正常工作

图片.png

利用defineReactive函数构造闭包环境,闭包环境具有内外两层嵌套的

图片.png val实际上造成了闭包环境,defineReactive()函数实际上相当于替代了临时变量(节省了设置临时变量)

图片.png

第四节课

递归侦测对象全部属性

图片.png

图片.png

图片.png

图片.png

第五节课

图片.png

图片.png

图片.png 以上三张图片循环调用 observe.js->Observer.js->defineReactive.js->observe.js

机制负荷下图规则

图片.png

图片.png

图片.png 结果

图片.png

第六节课

数组响应式原理

改写七种方法push pop shift unshift splice sort reverse
所有Array打点就能调用的方法都是来自于Array.prototype这个对象

图片.png Object.setPrototypeOf(o,arrayMethods)和o.prototypeOf=arrayMethods相等

Vue当中数组的响应式是如何实现的?
以Array.prototype为原型创建arrayMethods对象,
ES6提供了一个强制的方法Object.setPrototypeOf()
将数组的proto强制指向arrayMethods

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

第七节课

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

第八节课

依赖收集

需要用到数据的地方,称为依赖。
Vue1.x,细粒度依赖,用到数据都是依赖;
Vue2.x,中等粒度依赖,用到数据的组件都是依赖;
在getter方法中收集依赖,在setter方法中触发依赖
依赖就是Watcher,只有Watcher触发的getter才会收集依赖,哪个Watcher触发了
getter,就把哪个Watcher收集到Dep中。
Dep使用发布订阅模式,当数据发生变化时,会循环依赖列表,把所有的Watcher都通知一遍。
代码实现的巧妙之处:Watcher把自己设置到全局的一个指定位置,然后读取数据,因为读取了数据,
所以会触发这个数据的getter,在getter中就能得到当前正在读取数据的Watcher,并把这个Watcher
收集到Dep中。

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

第九节课