想着去了解vue的mvvm数据驱动是怎么实现的,百度中看了这篇文章,demo很好。其他文章只是讲到defineProperty的set,get。
我把文章的代码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实例去做的。
© 著作权归作者所有
举报
相关热门文章
发表评论
0/200