// 使用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