SOURCE

// 使用defineProperty对数据的get/set进行劫持
function Reactive(data) {
    for(let k in data) {
        let dep = new Dep()
        let oldVal = data[k]
        Object.defineProperty(data, k, {
            configurable: true,
            enumerable: true,
            get: function() {
                Dep.target ? dep.add() : undefined // Dep.target是Watcher实例,当存在Dep.target时,将依赖收集起来
                return oldVal
            },
            set: function(val) {
                oldVal = val
                dep.notify(val)  // set的时候通知依赖发生了改变
            }      
        })
    }
}

function Dep() {
    this.deps = []
    this.add = function() {
        this.deps.push(Dep.target)
    }
    this.notify = function(...args) {
        this.deps.forEach(watcher => watcher.effect(args))
    }
}
Dep.target = null

/*
 这个侦测机制的核心是: 数据发生了改变,如何让相应的副作用执行
 在Vue里,Watcher工作时,是先指定Dep.target = this, 然后在调用getter来触发Reactive里面的get方法
 这样就将当前watcher注册到了依赖中去
 */
function Watcher(getter, effect) {
    this.effect = effect
    Dep.target = this
    getter()
    Dep.target = null
}

// 测试
let obj = {name: `nowll`, age: 27}
Reactive(obj)

// 侦测name属性
new Watcher(() => obj.name, (newVal) => {
    console.log(`effect works!, newVal = ${newVal}`)
})

// 侦测name属性, 多个侦测都会运行
new Watcher(() => obj.name, (newVal) => {
    console.log(`this is another name effect`)
})

// 侦测age属性
new Watcher(() => obj.age, (newVal) => {
    console.log('this is age effect')
})

obj.name = 'Yang'
obj.age = 26
console 命令行工具 X clear

                    
>
console