1、创建观察者Observer类

Observer类主要是深度监听所有key值,(准备)收集所有依赖和等待被触发通知。
准备这两个字,是等待get/set触发。

什么个意思?就是说Observer类做深度的欲准备。

  1. class Observer{
  2. constructor(value){
  3. this.value = value
  4. if (Array.isArray(value)) {
  5. // 这里不做介绍 代码有点多
  6. } else {
  7. // Object的深度监听
  8. this.walk(value)
  9. }
  10. }
  11. walk(obj){
  12. const keys = Object.keys(obj)
  13. for(let i=0;i<keys.length;i++){
  14. defineReactive(obj,keys[i])
  15. }
  16. }
  17. }
  18. function defineReactive(obj,key,value){
  19. // 创建依赖Dep类
  20. const dep = new Dep()
  21. if(arguments.length===2){
  22. value = obj[key]
  23. }
  24. if (typeof value === 'object') {
  25. // 递归将子重新深度监听
  26. new Observer(value)
  27. }
  28. Object.defineProperty(obj, key, {
  29. configurable: true,
  30. enumerable: true,
  31. get() {
  32. // 在get中收集依赖
  33. dep.depend()
  34. return value
  35. },
  36. set(newVal) {
  37. if (value === newVal) {
  38. return
  39. }
  40. value = newVal
  41. // 在set中通知依赖
  42. dep.notify()
  43. }
  44. })
  45. }

2、创建Dep类

Dep依赖收集类,主要类中有:添加依赖,删除依赖,通知依赖。

  1. class Dep{
  2. constructor(){
  3. this.subs = []
  4. }
  5. addSub(sub){
  6. this.subs.push(sub)
  7. }
  8. removeSub(sub){
  9. remove(this.subs, sub)
  10. }
  11. depend() {
  12. if (window.target) {
  13. this.addSub(window.target)
  14. }
  15. }
  16. notify() {
  17. const subs = this.subs.slice()
  18. for (let i = 0; i < subs.length; i++) {
  19. subs[i].update()
  20. }
  21. }
  22. }
  23. function remove(arr, item) {
  24. if (arr.length > 0) {
  25. if (~arr.indexOf(item)) {
  26. return arr.splice(arr.indexOf(item), 1)
  27. }
  28. }
  29. }

3、Watcher监听类

watcher就是被Dep类收集起来的依赖
watcher做什么事情呢?
第一步:Watcher实例化,执行构造函数。

第二步:调用this.get方法,通过window.target = this把实例自身赋给了全局的一个唯一对象window.target上,然后通过let value = this.getter.call(vm, vm)获取被依赖的数据,获取被依赖数据的目的是触发该数据上面的getter,在getter里会调用dep.depend()收集依赖,而在dep.depend()中取到挂载window.target上的值并将其存入依赖数组中,在get()方法最后将window.target释放掉

第三步:当数据发生改变时,在Observer中setter中调用了dep.notify()方法,在dep.notify()方法中,遍历所有依赖(即watcher实例),执行依赖的update()方法,也就是Watcher类update实例方法

  1. class Watcher{
  2. constructor(vm,expOrFn,cb){
  3. this.vm = vm
  4. this.cb = cb
  5. this.getter = parsePath(expOrFn)
  6. this.value = this.get()
  7. }
  8. get () {
  9. window.target = this;
  10. const vm = this.vm
  11. let value = this.getter.call(vm, vm)
  12. window.target = undefined;
  13. return value
  14. }
  15. update () {
  16. const oldValue = this.value
  17. this.value = this.get()
  18. this.cb.call(this.vm, this.value, oldValue)
  19. }
  20. }
  21. const reg =/[^\w.$]/
  22. function parsePath(path) {
  23. if (reg.test(path)) {
  24. return
  25. }
  26. const segments = path.split('.') // userInfo.age => [userInfo,age]
  27. return function (obj) { // obj ={userInfo:{age:20}}
  28. for (let i = 0; i < segments.length; i++) {
  29. obj = obj[segments[i]]
  30. }
  31. return obj // 20
  32. }
  33. }