// Vue中是通过Object.defineProperty来进行数据劫持的
class Vue {
constructor(options) {
this.$el = options.el
this.$data = options.data
if (this.$el) {
new Observer(this.$data) // 让 $data里面的元素具有数据劫持的能力
new Compiler(this.$el, this)
}
}
}
// Observer类给我们$data中的某一些特定的数据添加数据劫持的能力, 也就是我们的getter 和 setter方法
class Observer {
constructor(data) {
this.observer(data)
}
observer(data) {
if (typeof data === 'object' && data != null) {
for (let key in data) {
this.defineReactive(data, key, data[key])
}
}
}
defineReactive(obj, key, value) {
this.observer(value)
let dep = new Dep() // 给每个数据添加被观察者
Object.defineProperty(obj, key, {
get() {
Dep.target && dep.addSub(Dep.target)
return value
},
set(newVal) {
if (newVal != value) {
this.observer(newVal)
value = newVal
dep.notify()
}
}
})
}
}
/**
// 观察者 - Watcher类
// Watcher类其实很简单,当我们被观察者发生变化的时候,观察者也会做出对应的变化。
// 观察者 数据一变化 调用回调更新视图
// Watcher内部会根据vm 和表达式如man.name等获取到当前表达式对应的$data的值,然后缓存起来,
当调用updata()方法的时候,如果新值和缓存起来的老值相等,则执行对应的回调函数来更新视图
**/
class Watcher {
constructor(vm, expr, cb) {
this.vm = vm
this.expr = expr
this.cb = cb
ths.oldVal = this.get() // 存放一个旧值
}
get() {
Dep.target = this // 将当前的watcher缓存在 Dep.target
let value = CompilerUnit.getVal(this.vm, this.expr)
Dep.target = null
return value
}
updata() {
let newVal = CompilerUnit.getVal(this.vm, this.expr)
if (newVal != this.oldVal) {
this.cb(newVal)
}
}
}
// 被观察者 - Dep类
// 有了观察者我们也需要有触发观察者update方法的被观察者
// 被观察者 自己的数据变化 通知所有观察者
class Dep {
constructor() {
this.subs = []
}
addSub(watcher) { // 订阅
this.subs.push(watcher)
}
notify() { // 发布
this.subs.forEach(watcher => watcher.updata())
}
}
console