简单实现vue中的依赖收集与响应的方法

声明一个对象man,可以视为vue中的data

let man = { height: 180, weight: 70, wealth: 100000000 }

添加Observer

作用在于将参数对象的属性变为响应式,只要对象的属性被读取或者被修改都能观察到。然后新建一个Observer实例,将man作为参数扔进去。这里的proxyData是将man的属性代理到以man为参数的Observer实例上去。

class Observer { constructor(obj) { this.walk(obj) } walk(obj) { Object.keys(obj).forEach(prop => { this[prop] = obj[prop] this.proxyData(obj, prop) this.defineReactive(this, prop, obj[prop]) }) } proxyData(obj, prop) { let _this = this Object.defineProperty(obj, prop, { get() { return _this[prop] }, set(newVal) { _this[prop] = newVal } }) } defineReactive(obj, prop, val) { Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被读取!`) return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) } }) } } new Observer(man)

这时打印一下man

简单实现vue中的依赖收集与响应的方法


现在man的属性都是由Observer实例所对应的属性的getter来返回,只有在查看时会被触发

简单实现vue中的依赖收集与响应的方法


对man的属性进行修改也会触发实例对应属性的setter

简单实现vue中的依赖收集与响应的方法

添加Watcher

现在的Watcher有点像vue中的computed,实际上就是定义一个计算属性,这个计算属性依赖于前面man中的某些属性,由他们计算而得。

class Watcher { constructor(obj, prop, computed) { this.getVal(obj, prop, computed) } getVal(obj, prop, computed) { Object.defineProperty(obj, prop, { get() { console.log(`computed属性 - ${prop}被读取!`) return computed() }, set() { console.error('计算属性不可被修改!') } }) } } new Watcher(man, 'strength', () => { let {height, weight} = man if (height > 160 && weight > 70) return 'strong' return 'weak' })

简单实现vue中的依赖收集与响应的方法


看起来没什么问题,所依赖的属性如果变了,计算属性只要再被查看(get方法)一次就可以更新了。但vue中的视图渲染是实时的,视图层依赖于数据层,数据变化了,视图层也会跟着变化,不需要手动更新。类比到这个例子就是计算属性如何才能在其所依赖的属性发生变化时被通知从而触发应有的事件?

这时我们先给Watcher加多一个callback,用于处理当依赖的数据被修改时,我这个计算属性该怎么响应

比如当依赖被修改时,我们就把这个计算属性的值打印出来

class Watcher { constructor(obj, prop, computed, callback) { this.getVal(obj, prop, computed, callback) } new Watcher(man, 'strength', () => { let {height, weight} = man if (height > 160 && weight > 70) return 'strong' return 'weak' }, () => { console.log(`i am so ${man.strength} !`) })

一切都准备好了,接下来就是该如何实现?

我们先看下Watcher中getVal这个方法

getVal(obj, prop, computed, callback) { Object.defineProperty(obj, prop, { get() { console.log(`computed属性 - ${prop}被读取!`) return computed() }, set() { console.error('计算属性不可被修改!') } }) }

当我们查看计算属性时,会调用computed这个方法,相当于查看了其所依赖的height和weight属性,而在上面我们已经让man的所有属性都拥有了get方法,即他们被查看时我们是不是可以把callback塞给他们?
这时候我们引进一个桥梁,来连接Watcher和Observer。

添加Dep

Dep的用处在于当某一个属性(以下称‘自己')被依赖了,将依赖自己的粉丝(们)--也就是Watcher(s),收集起来,假如自己发生了变化,能够及时通知粉丝们。

class Dep { constructor() { this.deps = [] } getDeps() { if (!Dep.target || this.deps.includes(Dep.target)) return console.log('依赖添加', Dep.target) this.deps.push(Dep.target) } notify() { this.deps.forEach(dep => { dep() }) } }

这里的Dep.target就是前面所说的callback方法了。这时我们改一下Watcher中的getVal

getVal(obj, prop, computed, callback) { Object.defineProperty(obj, prop, { get() { Dep.target = callback console.log(`computed属性 - ${prop}被读取!`) return computed() }, set() { console.error('计算属性不可被修改!') } }) }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/14e310c40b6dba295117bea495c634f2.html