看这篇以前,若是没有看过以前的文章,可拉到文章末尾查看以前的文章。vue
首先咱们思考一下截止当前,咱们都作了什么git
defineReactive
这个函数,实现了对于数据取值和设置的监听Dep
类,实现了依赖的管理Watcher
类,抽象出了对象下某个属性的依赖,以及属性变换的 callBack
对比 Vue
的 MVVM
(先把视图层的渲染抽象成一个函数),咱们仅仅是实现了一些基础性的东西。还有很大的区别,好比github
Watcher
仅仅是抽象了对象下的单一属性,而通常视图层的渲染是涉及多个属性的,而这些属性的变化是同一个渲染函数(也就是 Vue
中编译模板字符串最终生成的函数)。Watcher
的,换句话说就是,多个 Dep
依赖与同一个 Watcher
,那么 Watcher
中该如何保存这些 Dep
,由于按照咱们的实现,都一个 Watcher
中仅仅保持一个 Dep
先让咱们想一想,咱们是如何把依赖注入到 Dep
中的数组
经过取值触发 defineProperty
中的 get
,而后添加依赖函数
换句话说就是,我只要取过对应属性的值,那么就能够添加依赖。
看到以前 Watcher
的实现:测试
this.get = function () { Dep.target = this let value = this.getter.call(object) Dep.target = null return value }
这段代码就实现了添加相应属性的依赖,归根究竟是这段起了做用优化
let value = this.obj[this.getter]
这里触发了对应属性的 get
,那好针对第一个问题,咱们只要在这里触发多个属性的 get
便可,至于要触发那些属性,咱们交由调用者来控制,瓜熟蒂落的这里应该是一个函数。考虑以后便有了如下代码this
let Watcher = function (object, getter, callback) { this.obj = object // 这里的 getter 应该是一个函数 this.getter = getter this.cb = callback this.dep = null this.value = undefined this.get = function () { Dep.target = this // 将取值方式改为函数调用 let value = this.getter.call(object) Dep.target = null return value } this.update = function () { const value = this.getter.call(object) const oldValue = this.value this.value = value this.cb.call(this.obj, value, oldValue) } this.addDep = function (dep) { this.dep = dep } this.value = this.get() }
问题二其实很简单,既然要保存多个 dep 咱们把保存的值声明成一个数组便可code
let Watcher = function (object, getter, callback) { this.obj = object this.getter = getter this.cb = callback // 声明成数组 this.deps = [] this.value = undefined this.get = function () { Dep.target = this let value = this.getter.call(object) Dep.target = null return value } this.update = function () { const value = this.getter.call(object) const oldValue = this.value this.value = value this.cb.call(this.obj, value, oldValue) } this.addDep = function (dep) { // 将 dep 推入数组中 this.deps.push(dep) } this.value = this.get() }
为了方便取消这个 Watcher
,咱们在添加一个函数,用于取消全部 Dep
对 Watcher
的依赖,因此最终 Watcher
的代码以下:对象
let Watcher = function (object, getter, callback) { this.obj = object this.getter = getter this.cb = callback this.deps = [] this.value = undefined this.get = function () { Dep.target = this let value = this.getter.call(object) Dep.target = null return value } this.update = function () { const value = this.getter.call(object) const oldValue = this.value this.value = value this.cb.call(this.obj, value, oldValue) } this.addDep = function (dep) { this.deps.push(dep) } // 新添加的取消依赖的方法 this.teardown = function () { let i = this.deps.length while (i--) { this.deps[i].removeSub(this) } this.deps = [] } this.value = this.get() }
咱们仅仅优化了 Watcher
的实现,其余的代码并无发生变化
let object = {} defineReactive(object, 'num1', 2) defineReactive(object, 'num2', 4) let watcher = new Watcher(object, function () { return this.num1 + this.num2 }, function (newValue, oldValue) { console.log(`这是一个监听函数,${object.num1} + ${object.num2} = ${newValue}`) }) object.num1 = 3 // 这是一个监听函数,3 + 4 = 7 object.num2 = 10 // 这是一个监听函数,3 + 10 = 13 let watcher2 = new Watcher(object, function () { return this.num1 * this.num2 }, function (newValue, oldValue) { console.log(`这是一个监听函数,${object.num1} * ${object.num2} = ${newValue}`) }) object.num1 = 4 // 这是一个监听函数,4 + 10 = 14 // 这是一个监听函数,4 * 10 = 40 object.num2 = 11 // 这是一个监听函数,4 + 11 = 15 // 这是一个监听函数,4 * 11 = 44 // 测试取消 watcher2.teardown() object.num1 = 5 // 这是一个监听函数,5 + 11 = 16 object.num2 = 12 // 这是一个监听函数,5 + 12 = 17
这就实现了对于多个属性设置同一个监听,当监听函数中的依赖属性发生变化时,自动执行了相应的函数。
关于 Vue
中的 MVVM
的实现 ,差很少也就这样了,固然这仅仅是基础的实现,并且视图层层渲染抽象成一个函数。
不一样于 Vue
中的实现,这里少了不少各类标记和应用标记的过程。
这些会增长理解难度,以后有用到再说,实现完整的 MVVM
还须要对数组进行特殊的处理,由于数组是不能用 Object.defineProperty
来处理索引值的,这个也以后再说。