Vue源码数据侦测篇

Posted 三水草肃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue源码数据侦测篇相关的知识,希望对你有一定的参考价值。

  • Vue最大的特点就是数据驱动视图,动态变化,他由前一个状态到了后一个状态,页面也就应该变化,所以我们得到以下公式 UI = render(state)
    UI公式中:状态state是输入,页面UI输出,一旦状态发生改变,页面输出也就随之也改变,把这种特性称之为数据驱动视图。
  • 把UI公式分为三个部分,state,render(),UI。 state和UI都是用户顶的,不变的是render(),所以Vue就扮演了render()角色,当Vue发生state变化之后,经过一系列加公,最后变化反映在UI上

Vue变化侦测是: 追踪状态,亦或者是数据的变化,一旦发生了变化,就要去更新视图。
在React中变化侦测是通过对比虚拟DOM来实现变化侦测。

  • 数据驱动视图的关键点在于我们如何知道数据发生了变化,只要找到数据在什么时候变化了,那么问题就变得迎刃而解,我们只需要在数据变化的时候区通知视图更新即可。

  • 要将数据的视图可观测化,就要借助Object.defineProperty方法。

    • enumerable可枚举性用来控制所描述的属性,是否被包含在for…in循环之中,具体来说enumerable为false,下面三个操作不会取到该属性
    • for…in循环:取到的是索引
    • Object.keys方法:会返回一个由一个给定对象的自身可枚举属性组成的数组。传入对象,返回属性名。传入数组,返回索引。
    • JSON.stringify方法:用于将JS值转换为JSON字符串
    • enumerable: true可以遍历,false不可以遍历
    • configurable:true是可以删除和修改。 flase不可以修改
    • wriable: true是可写,flase是只读的

收集依赖:

  • 我们谁用了这个数据成为谁依赖了这个数据,我们给每个数据一个依赖数组,谁依赖了这个数据我们就把谁放入这个依赖数组中,那么这个数据发生变化的时候,我们就去它对应的依赖数组中,把每个依赖都通知一遍。
    在getter中收集依赖,在setter中通知依赖更新

  • 把依赖收集到哪里:更好的做法是为每一个数据都建立一个依赖管理器,把这个数据所有的依赖都管理起来。

  • 收集依赖到底是谁:Vue还实现了一个叫做watch的类,而watch类的实例就是我们上面说的那个谁,换句话说就是:谁用到了数据,谁就是依赖,我们就为谁创建一个watch的实例,在之后的数据变化的时候,我们不直接去通知依赖更新,而是通知依赖对应的watch实例,由watch实例去通知真正的视图

  • 总结:
    1. data通过watch转换成了getter/setter的形式来追踪变化
    2. 当外界通过watch读取数据的时候,会触发getter从而将watch添加到依赖中
    3. 当数据发生了变化时,会触发setter,从而向Dep中的依赖发送通知
    4. watch接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新,也有可能触发用户的某个回调函数等

数组变化侦测

  • 为什么Object和Array会有两种不同的变化侦测方式,这是因为对于Object数据我们使用的是JS提供的对象原型上的方法是Object.defineProperty,而这个方法是对象原型上,所以Array无法使用使用这个方法,所以我们需要对Array型数据设计一套另外的变化侦测机制

  • 根本思路还是不变的,就是:还是在获取数据的时候收起依赖,数据变化的时候通知依赖更新

  • Array型数据还是在getter中收集依赖

  • 数组的变化侦测:如何拦截数组的变化,可以通过在数组实例和Array.prototype之间,在拦截器内重写操作数组的一些方法,当数组实例使用操作数组的方法的时候,其实使用的是拦截器中重写的方法,而不再使用Araay.prototype上的原生方法.

以上是关于Vue源码数据侦测篇的主要内容,如果未能解决你的问题,请参考以下文章

Vue 3.0 源码分析-数据侦测

vue.js源码学习-双向绑定之Array

vue系列---响应式原理实现及Observer源码解析

vue2源码学习-响应式原理

vue2源码学习-响应式原理

Vue.js 源码分析(二十二) 指令篇 v-model指令详解