第4章 (第①篇 变化侦测)变化侦测相关的API实现原理

几个与变化侦测相关的常用API的内容原理

vm.$watch

vm.$watch(expOrFn,callback,[options])
【参数】:
1.{string|Function} expOrFn
2.{Function|Object} callback
3.{Object} [options] =>{boolean} deep =>{boolean} immediate
【返回值】:{Function} unwatch
【用法】:用于观察一个表达式或computed函数在Vue.js实例上的变化。回调函数调用时,会从参数得到新数据(new value)和旧数据(old value)。表达式只接受以点分隔的路径,例如a.b.c。如果是一个比较复杂的表达式,可以用函数替代表达式。

vm.$watch('a.b.c',function(newVal,oldVal){
    //做点什么
})

vm.$watch返回一个取消观察的函数,用来停止触发回调。

var unwatch = vm.$watch('xxx',function(){})
//取消观察
unwatch()

deep:为了发现对象内部值的变化,可以在选项参数中指定deep:true

vm.$watch('obj',function(){},{
    deep:true
})
vm.obj.value = '123';

*监听数组的变动不需要这么做
immediate:在选项参数中指定immediate:true,将立即以表达式的当前值触发回调

vm.$watch('a',function(){},{
    immediate:true    
})
//立即以'a'的当前值触发回调

watch的内部原理

vm.$watch实际上是对Watcher的一种封装,但是deep和immediate是Watcher中没有的。
vm.$watch执行new Watcher来实现基本功能
expOrFn是支持函数的,新增对于expOrFn的判断,如果是函数,直接将值赋给getter,如果不是函数,则使用parsePath函数来读取keypath中的数据,keypath是属性路径,例如a.b.c,说明从vm.a.b.c中读取数据。
当时函数时,不只可以动态返回数据,读取的所有数据都会被Watcher观察,如果是字符串则会读取这个keypath所指向的数据并观察变化,函数则会同时观察函数中读取的所有Vue.js实例上的响应式数据。
最后函数返回一个unwatch用来取消观察数据,事实上执行这个函数时,其实时执行了Watcher.teardown()来取消观察数据,本质是把Watcher实例从当前正在观察的状态的依赖列表中移除。teardown其实就是需要在Watcher中记录自己订阅了谁,那些dep收集了watcher实例,当要取消订阅的时候,则循环自己记录的订阅列表来通知Dep把自己从Dep的依赖列表中移除。

deep参数实现原理

其实就是除了要触发当前监听数据的收集依赖的逻辑之外,还要把当前监听的这个数据在内的所有子值都触发一遍收集依赖,然后当这个依赖的所有子数据发生变化的时候就会通知当前Watcher了。
如果用户设置了deep参数,则用一个叫做traverse的函数在window.target=undefined之前来处理deep逻辑。如果不在这个语句之前去触发子值的收集依赖,不能保证子集收集的依赖是当前的Watcher
traverse函数:先判断val的类型,如果不是数组或者是对象就直接返回什么都不干,如果是拿到val的dep.id来保证不重复收集依赖,如果是数组,则循环每一项递归调用_traverse,如果是对象,就循环所有key,执行一次读取操作,再递归子值。

vm.$set

vm.$set(target,key,value)
【参数】:
1.{Object|Array} target
2.{String|Number} key
3.{any} value
【返回值】:{Function} unwatch
【用法】:在object上设置一个属性,如果object是响应式的,vue会保证属性被创建后也是响应式的,并且触发视图的更新。这个方法主要是用来避开Vue.js不能侦测属性被添加后的限制。
*注意:target不能是Vue.js实例(使用target._isVue来判断)或者Vue.js实例的根数据对象(使用ob.vmCount来判断)。

vm.$set用来解决之前无法侦测新增属性的问题,例如直接使用this.obj.name=xxx来添加属性

vm.$delete

delete语句删除的的属性,Vue无法侦测到数据发生了变化,使用vm.$delete来删除数据中的某个属性,此时就可以侦测到数据发生的变化

vm.$delete(target,key)
【参数】:
1.{Object|Array} target
2.{String|Number} key/index
【用法】:删除对象的属性。如果对象是响应式的,需要确保删除能触发更新视图。这个方法主要用于避开Vue.js不能检测到属性被删除的限制。

和set差不多,就是删除查找到对应的索引位置使用splice方法删除然后通知依赖,找不到数据就什么都不做,找到了不是响应式就删除就行,如果是就通知依赖。

深入浅出Vue.js 文章被收录于专栏

记录一下阅读vue源码的收获

全部评论

相关推荐

双尔:反手回一个很抱歉,经过慎重考虑,您与我的预期暂不匹配,感谢您的投递
点赞 评论 收藏
分享
来,说点可能被同行“骂”的大实话。🙊当初接数字马力Offer时,朋友都说:“蚂蚁的“内包”公司?你想清楚啊!”但入职快一年后的今天,我反而对他有了不一样的看法!🔹 是偏见?还是信息差!之前没入职之前外面都在说什么岗位低人一等这类。实际上:这种情况不可至否,不能保证每个团队都是其乐融融。但我在的部门以及我了解的周边同事都还是十分好相处的~和蚂蚁师兄师姐之间也经常开一些小玩笑。总之:身份是蚂蚁公司给的,地位是自己挣的(一个傲娇女孩的自述)。🔹 待遇?玩的就是真实!试用期工资全额发!六点下班跑得快(早9晚6或者早10晚7,动态打卡),公积金顶格交。别听那些画饼的,到手的钱和下班的时间才是真的(都是牛马何必难为牛马)。🔹 能不能学到技术?来了就“后悔”!我们拥有权限直通蚂蚁知识库,技术栈多到学不完。说“学不到东西”的人,来了可能后悔——后悔来晚了(哈哈哈哈,可以不学但是不能没有)!💥 内推地址:https://app.mokahr.com/su/ueoyhg❗我的内推码:NTA6Nvs走我的内推,可以直达业务部门,面试流程更快速,进度可查!今天新放HC,之前挂过也能再战!秋招已经正式开始啦~机会就摆在这,敢不敢来试一试呢?(和我一样,做个勇敢的女孩)
下午吃泡馍:数字马力的薪资一般哇,5年经验的java/测试就给人一万出头,而且刚入职第三天就让人出差,而且是出半年
帮你内推|数字马力 校招
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务