zoukankan      html  css  js  c++  java
  • Vue主要原理最简实现与逻辑梳理

    Vue的主要原理中主要用到了定义的这么几个函数Dep,Watcher,observer。
    我们来使用这几个函数简单的实现一下vue构造函数数据绑定和相互依赖部分,梳理一下它们之间的关系。
    省略了编译部分和proxy代理与其他的一些复杂逻辑。

    Dep

    Dep是依赖类,简要实现为

    
    class Dep {
      constructor () {
        // 放当时属性的观察者
        this.subs = []
      }
    }
    // target 用来挂载当时的watcher观察者
    Dep.target = null
    

    observer

    做属性劫持,并做点其他事情

    
    
    function observer (vm, key, val) {
      let dep = new Dep()
      Object.defineProperty(vm, key, {
        /**
         * get主要做两个事情
         * 1. 收集观察当前key的wathcer(即依赖当前key的操作)
         * 2. 获取值
         */
        get () {
          // 这是作用1
          if (Dep.target) {
            dep.subs.push(Dep.target)
          }
          // 这是作用2
          return val
        },
        /**
         * set也是两个事情
         * 1. 修改目标值
         * 2. 执行依赖当前key的watcher
         */
        set (newVal) {
          // 这是作用1
          val = newVal
          // 这是作用2
          for(cb of dep.subs) {
            cb.call(vm)
          }
        }
      })
    }
    

    Watcher

    Watcher是观察者类,用来创建依赖某属性的操作(如指令,渲染,计算属性等)

    
    class Watcher {
      /**
       * vm: 实例
       * cb: 依赖某属性的操作函数
       */
      constructor (vm, cb) {
        // 把当前的操作挂载到Dep上
        Dep.target = cb
        /**
         * 执行操作,两个作用
         * 1. 进行操作的初始化
         * 2. 触发属性的get方法,使当前cb被收集
         */
        cb.call(vm)
        Dep.target = null
      }
    }
    

    demo

    那么我们就使用上面定义好的函数写个例子

    ```<div> <p class="text"></p> <div> ```
    
    let vm = new Vue({
      // 假设有data
      data: {msg: 1},
      // 有某个v-text操作,我们抽象为vText函数,依赖属性msg(代表所有依赖其他属性的操作)
      renderFun: {
        vText () {
          document.querySelector('.text').innerText = this.msg
        }
      }
    })
    // 修改vue实例的值,观察变化
    vm.msg = 333
    

    那么我们也写一个vue的简易构造函数

    
    class Vue {
      constructor (options) {
        let data = options.data
        let renderFun = options.renderFun
        // initData
        Object.keys(data).forEach(key =&gt; {
          observer(this, key, data[key])
        })
        // 模拟计算属性,watcher,指令等依赖属性的操作
        Object.keys(renderFun).forEach(key =&gt; {
          new Watcher(this, renderFun[key])
        })
      }
    }
    

    执行过程

    完整的代码可以看demo部分的两个链接

    1. 创建vue实例,执行new Vue()
    2. 对data进行初始化,对data中属性进行属性劫持

      • 劫持过程中,在闭包内创建对当前属性的依赖队列(dep.subs)和值(val)。get进行观察者watcher的收集和值得获取;set进行值的更新和依赖队列中watcher的执行
    3. 对编译过程中如computedwatcher模板编译过程中的指令函数进行初始化,我们以renderFun代替
    4. 针对renderFun中的每个功能函数进行new Watcher()工作
    5. vText为例子,在new Wathcer()过程中

      1. vText挂载到全局通用的Dep.target
      2. 执行vText,其中有读vm.msg的操作,则触发msg属性的get,进入Dep.target判断,将Dep.targetvText收集进msgsubs依赖队列中,此时vText执行完毕,页面innetText被修改
      3. Dep.target置空
    6. 执行vm.msg = 333,则触发msgset

      1. set先修改msg的值
      2. 再执行msg依赖队列中的所有watcher的函数,即vText,页面的innerText被同步更新

    总结

    总之几者的关系就是在observerget中将对当前属性的watcher收集进dep,在observerset中执行收集到的watcher

    而vue的真正的执行过程绝不是上面写的这么简单,比如watcher的执行就绝不是简单的遍历执行,而且还对observer进行了很大程度的简化。我们还省略了诸如_proxydefineReactive等出现频率较高的函数。写这样一个最简实现主要是为了梳理一下主干,降低阅读源码的难度。

    ??????????????????????????????????

    原文地址:https://segmentfault.com/a/1190000014195710

  • 相关阅读:
    数据变换
    离群点的检验
    数据清洗
    数据采样
    FM与FFM
    EM算法与高斯混合模型
    最大熵模型
    PageRank
    软件技术基础
    原来炫酷的可视化地图,用Python就能搞定!
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9919470.html
Copyright © 2011-2022 走看看