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) : valif (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) : valif (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()
