SOURCE

class Dep {
  constructor () {
    // 定义一个收集对应属性依赖的容器
    this.subs = []
  }
  // 收集依赖的方法
  addSub () {
    // Dep.target是个全局变量,用于存储当前的一个watcher
    this.subs.push(Dep.target)
  }
  // set方法被触发时会通知依赖
  notify () {
    for (let i = 1; i < this.subs.length; i++) {
      this.subs[i].cb()
    }
  }
}

Dep.target = null

class Watch {
  constructor (exp, cb) {
    this.exp = exp
    this.cb = cb
    // 将Watch实例赋给全局变量Dep.target,这样get中就能拿到它了
    Dep.target = this
    data[exp]
  }
}

function defineReactive (data, key, val) {
  observer()
  let dep = new Dep() // 新增:这样每个属性就能对应一个Dep实例了
  Object.defineProperty(data, key, {
    configurable: true,
    enumerable: true,
    get () {
      dep.addSub() // 新增:get触发时会触发addSub来收集当前的Dep.target,即watcher
      return val
    },
    set (newVal) {
      if (newVal === val) {
        return
      } else {
        data[key] = newVal
        observer(newVal)
        dep.notify() // 新增:通知对应的依赖
      }
    }
  })
}

// 定义一个类供传入监听数据
class Observer {
  constructor(data) {
    let keys = Object.keys(data)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(data, keys[i], data[keys[i]])
    }
  }
}
// 递归判断
function observer (data) {
  if (Object.prototype.toString.call(data) === '[object Object]') {
    new Observer(data)
  } else {
    return data
  }
}

// ================
// 需要劫持的数据
let data = {
  a: 1,
  b: {
    c: 3
  }
}

// 劫持数据data
observer(data)

// 监听订阅数据data的属性
new Watch('a', () => {
    alert(1)
})
new Watch('a', () => {
    alert(2)
})
new Watch('b.c', () => {
    alert(3)
})

data.a = 33
console.log(data,'data')

console 命令行工具 X clear

                    
>
console