Vue的双向绑定主要做了2件事
- 数据劫持
- 添加观察者
数据劫持(proxy)+依赖收集(观察者模式:watcher、Dep)
数据劫持
Object.defineProperty
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
# 这里无非就是劫持了对象的get和set方法。在所代理的属性的get方法中,
# 当dep.Target存在的时候会调用 dep.depend(),
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
}
if (Array.isArray(value)) {
dependArray(value)
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})
proxy
// 最新版可以通过 Proxy 实现
Proxy(data, {
get(target, key) {
return target[key];
},
set(target, key, value) {
let val = Reflect.set(target, key, value);
_that.$dep[key].forEach(item => item.update());
return val;
}
})
观察者模式
btw:观察者模式 vs 发布订阅
eventemitter属于?
// 订阅者:数据变更的消费者
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
depend() {
if (Dep.target) {
Dep.target.addDep(this);
}
}
notify() {
this.subs.forEach(sub => sub.update())
}
}
// 被观察者:数据变更了通知下游消费者
class Watcher {
constructor(vm, expOrFn) {
this.vm = vm;
this.getter = expOrFn;
this.value;
}
get() {
Dep.target = this;
var vm = this.vm;
var value = this.getter.call(vm, vm);
return value;
}
evaluate() {
this.value = this.get();
}
addDep(dep) {
dep.addSub(this);
}
update() {
console.log('更新, value:', this.value)
}
}
// 观察者实例
var dep = new Dep();
// 被观察者实例
var watcher = new Watcher({x: 1}, (val) => val);
watcher.evaluate();
// 观察者监听被观察对象
dep.depend()
dep.notify()
- 通过 watcher.evaluate() 将自身实例赋值给 Dep.target
- 调用 dep.depend() 将dep实例将 watcher 实例 push 到 dep.subs中
- 通过数据劫持,在调用被劫持的对象的 set 方法时,调用 dep.subs 中所有的 watcher.update()