vue响应式系统原理解析

编写一个mini观察器来解析Vue2.0的响应式系统。

可能大部分人都已知道了Vue2.0是采用Object.defineProperty()这个API进行实现,现在我们从0开始通过Object.defineProperty()编写一个mini观察器理解Vue响应式的原理思路。

1、getter 和 setter

实现一个转换函数(或者说是拦截函数),对对象中的属性进行set和get。

使用log查看是否有执行

function convert(obj) {
  Object.keys(obj).forEach(key => {
    let val = obj[key];
    Object.defineProperty(obj, key, {
      get() {
        console.log('get val')
        return val;
      },
      set(newVal) {
        console.log(`set ${newVal} to ${key}`)
        val = newVal;
      }
    })
  })
}

2、依赖追踪

就是追踪当data改变时哪些代码应该执行。

定义一个Dep类,至少应该包含depend(收集)和 notify(唤醒)这两个方法。

class Dep{
  depend() {}
  notify() {}
}

同时需要定义一个数组用于保存已经收集的信息

class Dep{
  constructor() {
    this.subs = new Set()
  }
  depend() {
  // 判断是否存在更新函数
    if(activeUpdate) {
      this.subs.add(activeUpdate)
    }
  }
  notify() {
    this.subs.forEach(sub => sub())
  }
}

写一个获取更新函数的方法。

let activeUpdate

function run(update) {
  function wrapper() {
    activeUpdate = wrapper;
    update();
    activeUpdate = null;
  }
  wrapper();
}

可能上面的代码有点难懂,我们先整合一下setter和getter中的方法,在结合着理解。

在get方法中添加依赖方法,在set方法中添加唤醒方法,可能有些看过源码的好兄弟们反映过来了,这不就是observe方法嘛。是的,那就改一下函数名称。

function observe(obj) {
  Object.keys(obj).forEach(key => {
    let val = obj[key];
    let dep = new Dep()
    Object.defineProperty(obj, key, {
      get() {
      // 收集
        dep.depend()
        console.log('get val')
        return val;
      },
      set(newVal) {
      // 判断是否更新
        const hasChanged = val !== newVal
        if(hasChanged) {
          console.log(`set ${newVal} to ${key}`)
          val = newVal;
          dep.notify()
        }
      }
    })
  })
}

我们重点看一下get方法中的dep.depend()。它是怎么将代码进行收集的呢?

先随便定义一个数据进行响应式处理

const state = { count: 0 }
observe(state)
run(() => { console.log(` count is  ${state.count}`) })

我们都知道js是单线程的,在同一时间只能执行一个函数。

我们在执行run(() => { console.log( count is ${state.count}) }) 这个方法时,执行的是run 内部的 wrapper 方法。 给activeUpdate赋值为wrapper(), 然后执行update()方法。

update()方法中我们访问了state.count属性,就会调用get()方法,因此会执行dep.depend(),在类Dep中的depend()方法中就可以根据activeUpdate是否为undefined进行依赖添加。

最后改变count的值就可以发现可以监听到数据的变化。

state.count = 1

你可能感兴趣的:(vue,javascript,vue,js)