vue实现双向数据绑定原理(数据劫持和发布订阅者)的个人理解注释

<script>
  //创建依赖收集的类
  export class Dep {
    constructor() {
      this.subs = []
    }
    //为添加依赖添加方法 我也不知道为什么要定义这个函数 直接写在depend不香么? 完成API? 或许有其他的用法
    addSubs(sub) {
      this.subs.push(sub)
    }
    //删除依赖 or 接触监听
    removesubs() {
      remove(this.subs, sub)
    }
    //添加依赖
    depend() {
      if (window.target) {
        //判断全局中有咩有watcher绑定了window.target 有就收集
        addSubs(window.target)
      }
    }
    //发送通知到依赖 提醒依赖更新
    notify() {
      const subs = this.subs.slice() //或许是怕修改到原数组吧 因为slice方法不会影响到原数组
      for (let i = 0; i < this.subs.length; i++) {
        this.subs[i].update() //watcher中定义了update方法
      }
    }
  }
  //删除依赖
  function remove(arr, item) {
    if (arr.length) {
      if (arr.indexOf(item) > -1) {
        const index = Object.keys(arr)
        arr.splice(index, 1)
      }
    }
  }
  //收集object中的全部子key 递归回调 创建Observer类 把全部都变成getter/setter的形式
  export class Observer {
    constructor(val) {
      //判断是不是数组
      if (!Array.isArray(val)) {
        walk(val)
      }
    }
  }
  function walk(val) {
    let keys = Object.keys(val)
    for (let i = 0; i < val.length; i++) {
      defineReactive(val, keys[i], val[keys[i]]) // 这里的val[keys[i] 是key中key 是为了判定key还有没有其他的对象
    }
  }
  //订阅者watcher 也就是依赖
  export class Watcher{
    constructor(vm, expOrFn, cb) {
      this.vm = vm;
      this.cb = cb;
      this.getter = parsePath(expOrFn) //获取data.a.b.c的内容
      this.value = this.get(); // 当前值
    }
    get() { //获取当前的属性
      window.target = this; //绑定当前目标
      let val = this.getter.call(this.vm, this.vm) //把当前的路径放入这个watch对象中 获取当前数据
      window.target = undefined;//取消为了下次获取
      return val
    }
    update() {
      //获取当前记录
      let oldval = this.value;
      //获取最新记录
      let val = this.get()
      //回调更新视图 //把this.cb的全部方法属性放到this.vm这个对象里 然后在把参数传进this.vm里
      this.cb.call(this.vm, val, oldval)
    }
  }
  //实现数据劫持和变化侦测
  function defineReactive(data, key, val) {
    if (typeof val === 'object') {
      new Observer(val)
    }
    let dep = new Dep() //实例化类
    Object.defineProperty(data, key, {
      enumerable: true, //可以枚举
      configurable: true, //可删除
      get: function () {
        //get不用传值 因为在收集到的依赖Watcher中绑定了window.target
        //这里是收集依赖的
        dep.depend() //在dep类中定义了depend方法
        return val
      },
      set: function (newVal) {
        //set要传newVal
        if (val === newVal) {
          return
        }
        val = newVal //更新新的newVal 不然会一直触发set(个人猜测)
        dep.notify() //在dep类中定义了notify方法
      },
    })
  }
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值