Vue的响应式原理

225 阅读3分钟

Vue的响应式原理是通过数据劫持+观察者模式来实现的

数据劫持

观察vue中打印出来的数据发现有奇奇怪怪的get,set,这是因为Vue会对data中数据进行数据劫持,并对data中的数据进行数据代理

  • Vue中的数据代理

    • 通过vm对象来代理data对象中的属性的操作(读/写)
  • Vue中数据代理的好处

    • 更加方便的操作data中的数据
  • 基本原理

    • 通过Object.defineProperty()把data对象中所有的属性添加到vm上。为每一个添加vm上的属性,都指定一个getter/setter.在getter/setter内部去操作(读/写)data中对应的属性
  • 模拟Vue的数据代理 `

      let data = {
          name: '尚硅谷',
          address: '北京'
      }
    
      // 创建一个实例对象,用于监视data中属性的变化
      const obs = new Objserver(data)
      console.log(obs);
    
      // 准备一个vm实例对象
      let vm = {};
      vm._data = data = obs;
    
      function Objserver(obj) {
          // 汇总对象中所有的属性形成一个数组
          const keys = Object.keys(obj);
          //遍历
          keys.forEach(function(k){
              Object.defineProperty(this,k,{
                  get(){
                      return obj[k];
                  },
                  set(val){
                      console.log(`${k}被改了,我要去解析模板,生成虚拟DOM......我要开始忙了`);
                      obj[k] = val;
                  }
              })
          })
    
      }
    

    `

  • 实现一个迷你版的数据响应式

image.png

观察者模式

  • 定义: 定义对象间一种“一对多”的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知
  • 与发布订阅模式的区别:少了一个中间代理,发布者直接面向订阅者 image.png

image.png

  • 观察者模式的的四大核心类
    • Observer类: (数据劫持)数据的观察者,让数据对象的读写操作都处于自己的监管之下
    • Watcher类:数据的订阅者,数据的变化会通知到Watcher,然后由Watcher进行相应的操作,例如更新视图
    • Dep类:上带有添加、解绑以及通知订阅者的方法;Observer把数据进行劫持从而数据变了我们是知道的,但是数据变了谁去通知订阅者呢?是Dep 它是 Observer与Watcher的纽带,当数据变化时,会被Observer观察到,然后由Dep通知到Watcher
    • Compile类: Compile干的活是解析模板指令,将模板中的变量替换成数据,然后初始化渲染视图,并将每个指令对应的节点绑定更新函数,监听数据的订阅者,一旦有异动,就去更新视图

总结:

  • 数据劫持的目的是:数据变了的时候程序知道
  • 观察者模式:一个数据变了 视图中多个地方都会变

话术:

  • vue是响应式,所谓的响应式是指数据发生改变的时候,视图会重新渲染,vue实现响应式的原理是数据劫持和观察者模式 数据劫持实现了数据改变程序是知道的,观察者模式实现了当一个数据变了,视图中多个用到的地方跟着变
  • 实现原理是:
    • 首先,通过Observer类对data中的数据利用Object.defineProperty进行数据劫持把data中所有的属性转换成getter和setter的写法,在getter中会让每个数据都创建一个发布者dep实例对象,一个数据对应一个dep实例
    • 然后,通过Compile类对模板进行编译得到和data中属性相对应的Watcher订阅者,把订阅者加入到dep中,这是一对多的关系
    • 最后,当data中数据改变的时候,会通知对应的dep,dep会对这个数据相对应的所有的订阅者Watcher进行遍历通知, Watcher会更新相对应的视图

image.png

image.png