VUE - MVVM - part2 - Dep
看这篇之前,如果没看过 step1
先移步看 实现 VUE 中 MVVM - step1 - defineProperty。
在上一篇我们大概实现了,Vue
中的依赖收集和触发,但我们仅仅是将依赖维护在一个内置数组中,这样做虽然容易理解,但毕竟不好维护,为了更容易的维护这些依赖,我们来实现一个维护依赖的类。
确定功能
首先我们可以先确定这个类下的属性,以及一些功能:
类下属性:
- target 函数,用于存放需要添加的依赖
实例下属性及方法:
- subs/Array 用于存放依赖
- addSub/Function 用于添加依赖
- removeSub/Function 用于移除依赖
- notify/Function 用于执行依赖
实现
考虑到直接放在浏览器上执行,所以直接用 ES5
的类写法。
let Dep = function(){ // 实例属性 this.subs = [] // 实例方法 this.addSub = function(sub){ this.subs.push(sub) } this.removeSub = function(sub){ const index = this.subs.indexOf(item) if (index > -1) { this.subs.splice(index, 1) } } this.notify = function(newValue, oldVaule){ this.subs.forEach(fnc=>fnc(newValue, oldVaule)) } } // 类属性 Dep.target = null
好了,现在我们拥有了一个管理依赖的类(这里将依赖简化为一个方法),现在我们就可以动手来改一下之前的代码了。
let defineReactive = function(object, key, value){ let dep = new Dep() Object.defineProperty(object, key, { configurable: true, enumerable: true, get: function(){ if(Dep.target){ dep.addSub(Dep.target) } return value }, set: function(newValue){ if(newValue != value){ dep.notify(newValue, value) } value = newValue } }) }
可以发现,之前我们用来存放依赖的数组变成了一个依赖管理(Dep
)的实例。同样的,在取值时收集依赖,在设置值(当值发生变化)时触发依赖。
由于依赖的处理由 Dep
的实例管理了,这里仅仅调用一下相关方法即可。
接下来试一试效果:
let object = {} defineReactive(object, 'test', 'test') Dep.target = function(newValue, oldValue){ console.log('我被添加进去了,新的值是:' + newValue) } object.test // test Dep.target = null object.test = 'test2' // 我被添加进去了,新的值是:test2 Dep.target = function(newValue, oldValue){ console.log('添加第二个函数,新的值是:' + newValue) } object.test // test Dep.target = null object.test = 'test3' // 我被添加进去了,新的值是:test3 // 添加第二个函数,新的值是:test3
但是上面的代码暴露了几个问题
Dep
这个类将监听属性和处理依赖进行了解耦,但是却没有完全解耦,在触发依赖的时候,还是得传新旧值。- 上面代码中
Dep
中定义的removeSub
在代码中并没有用到,因为Dep
的实例是在defineReactive
函数的作用域中,外部并不能直接调用,而删除依赖肯定是在外部的环境中,也就是说即使我们将代码改成这样,我们还是不能直接取删除已经没用的依赖。
Vue
中实现了一个 Watcher
的类来处理以上两个问题,之后再说。
以下 ES6
语法下的 Dep
,Vue
源码中差不多就这样
class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } removeSub(sub) { const index = this.subs.indexOf(item) if (index > -1) { this.subs.splice(index, 1) } } notify() { this.subs.forEach(fnc=>fnc(oldValue, newValue)) } } Dep.target = null
系列文章地址
- VUE - MVVM - part1 - defineProperty
- VUE - MVVM - part2 - Dep
- VUE - MVVM - part3 - Watcher
- VUE - MVVM - part4 - 优化Watcher
- VUE - MVVM - part5 - Observe
- VUE - MVVM - part6 - Array
- VUE - MVVM - part7 - Event
- VUE - MVVM - part8 - 优化Event
- VUE - MVVM - part9 - Vue
- VUE - MVVM - part10 - Computed
- VUE - MVVM - part11 - Extend
- VUE - MVVM - part12 - props
- VUE - MVVM - part13 - inject & 总结
相关推荐
XCMercy 2020-07-19
源码zanqunet 2020-10-28
theowl 2020-08-18
qiximiao 2020-08-03
风萧萧梦潇 2020-07-28
Andrewjdw 2020-07-26
huakai 2020-07-26
georgeandgeorge 2020-07-19
Jonderwu 2020-07-19
源码物语 2020-07-18
XGQ 2020-06-21
aNian 2020-06-16
郴州小程序 2020-06-13
园搬家测试账号 2020-06-12
Wonder的学习 2020-06-08
小方哥哥 2020-06-07
LULUBAO 2020-06-05
学习备忘录 2020-06-03
RocNg 2020-06-01