摘要:看这篇之前,如果没看过先移步看实现中。同样的,在取值时收集依赖,在设置值当值发生变化时触发依赖。中实现了一个的类来处理以上两个问题,之后再说。以下语法下的,源码中差不多就这样点击查看相关代码系列文章地址优化优化总结
看这篇之前,如果没看过 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 & 总结
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/94133.html
摘要:解决第一个问题很简单,我们把某个属性的值对应值变化时需要执行的函数抽象成一个对象,然后把这个对象当成是依赖,推入依赖管理中。的实现有了以上的考虑,那个依赖对象在中就是。新值作为添加的第一个函数,很自豪。 看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。 前言 在 step2 中,我们实现了一个管理依赖的 Dep ,但是仅仅使用这个类并不能完成我们想实现的功能,而且代码...
摘要:关于中的的实现,差不多也就这样了,当然这仅仅是基础的实现,而且视图层层渲染抽象成一个函数。不同于中的实现,这里少了很多各种标记和应用标记的过程。 看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。 回顾 首先我们思考一下截止当前,我们都做了什么 通过 defineReactive 这个函数,实现了对于数据取值和设置的监听 通过 Dep 类,实现了依赖的管理 通过 Wa...
摘要:回顾在前面的几个中,我们实现对象的属性的监听,但是有关于数组的行为我们一直没有处理。并且上述的几个数组方法是数组对象提供的,我们要想办法去触发下的函数。在设置值的时候就能成功触发依赖。 看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。 回顾 在前面的几个 step 中,我们实现对象的属性的监听,但是有关于数组的行为我们一直没有处理。我们先分析下导致数组有哪些行为: ...
摘要:具体代码执行方式进入到的目录下,命令行运行即可。确保为一个对象如果对象下有则不需要再次生成函数返回该对象的实例,这里判断了如果该对象下已经有实例,则直接返回,不再去生产实例。这就确保了一个对象下的实例仅被实例化一次。 看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。 回顾 在 step4 中,我们大致实现了一个 MVVM 的框架,由3个部分组成: defineRe...
摘要:在中关于如何实现在网上可以搜出不少,在看了部分源码后,梳理一下内容。换个说法,当我们取值的时候,函数自动帮我们添加了针对当前值的依赖,当这个值发生变化的时候,处理了这些依赖,比如说节点的变化。 在 VUE 中关于如何实现在网上可以搜出不少,在看了部分源码后,梳理一下内容。 首先,我们需要了解一下 js 中的一个 API :Object.defineProperty(obj, prop,...
阅读 3017·2021-10-27 14:16
阅读 2854·2021-09-24 10:33
阅读 2237·2021-09-23 11:21
阅读 3209·2021-09-22 15:14
阅读 747·2019-08-30 15:55
阅读 1644·2019-08-30 15:53
阅读 1695·2019-08-29 11:14
阅读 2174·2019-08-28 18:11