想着去了解vue的mvvm数据驱动是怎么实现的,百度中看了这篇文章,demo很好。其余文章只是讲到defineProperty的set,get。
完全理解Vue中的Watcher、Observer、Depvue
我把文章的代码demo简化成本身的代码而且作了注释
class Observer { constructor(targetObject) { //console.log('targetObject',targetObject); //def(targetObject, '__ob__', this);//在 targetObject 上 添加 Observer 实例, setter时 通知该实例 Object.defineProperty(targetObject, '__ob__', { value: this, //enumerable: !!enumerable, writable: true, configurable: true }); //给对象的每一个属性设置get set方法 Object.keys(targetObject).forEach(key => { //console.log('targetObject',targetObject,'key',key,'targetObject[key]',targetObject[key]); defineReactive(targetObject, key, targetObject[key])//给对象(包括对象内的对象)定义GET SET方法 }); //给每一个Observer都添加dep实例 this.dep = new Dep() //手动执行订阅 //this.dep.depend() } } function observe(data) { if (Object.prototype.toString.call(data) !== '[object Object]') { return } new Observer(data) } function defineReactive(obj, key, val) { //再去判断对象属性的值是否是对象,是的话给该对象也新增__ob__属性 observe(val) //上面的oberve()执行完毕以后对象内全部的对象都有__ob__属性 //去给对象(包括对象内的对象)设置get set方法 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { console.log('get'); const ob = this.__ob__ ob.dep.depend(); return val }, set: function reactiveSetter(newVal) { console.log('set'); if (newVal === val) return val = newVal observe(newVal)//新值若是是对象也要给其设置__ob__(值为Observer实例) const ob = this.__ob__ ob.dep.notify(newVal); }, }) } class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } depend() { this.subs.push(Dep.target) } notify(val) { for (let i = 0; i < this.subs.length; i++) { this.subs[i].fn(val) } } } Dep.target = null class Watcher { constructor(vm, exp, fn) { //console.log('vm',vm,'exp',exp,'fn',fn) this.vm = vm this.exp = exp this.fn = fn Dep.target = this//将本身挂载到 Dep.target,调用 Dep.depend时会读取该变量 this.vm[exp]//取值 触发get方法 依赖 } } //实验代码 const obj = { a: 1, b: { c: 2 } } new Observer(obj) console.log('给obj内全部对象设置__ob__以及SET,GET方法',obj) //在obj这个对象去监听a这个属性的变化(执行订阅) new Watcher(obj, 'a', (val) => { console.log('obj.a设置了新值了',val); }) obj.a='222';
全部Vue中的MVVM是用Object.defineProperty和订阅者模式实现的。 设置GET动做是去添加依赖(订阅),SET方法是根据依赖(订阅)菜单去发布更新的值,而真正去作动做的(好比更新到DOM中去)是__ob__的值(即observer)中dep中每一个watcher实例去作的。