简单实现Vue的observer和watcher(2)

在谷歌浏览器的console中粘贴以上代码,然后回车发现,结果不出所料,va本身被监听了,可以,我们试试va的内部属性有没有被监听,改下vm.data.va=1为vm.data.va.a = 1,结果发现报错了

什么鬼?

我们又仔细检查了代码,WTF,原来我们在递归的时候,Object.defineProperty中的回调函数cb的key参数一直在发生变化,我们希望的是里面的属性变化的时候执行的是我们事先定义好的回调函数~那么我们来改下方法,将一开始定义好的回调作为参数传进去,确保每一层递归set的回调都是我们事先设置好的~

var vm = { _data: {}, $data: {}, callback: {}} var defineReactive = (obj, key, cb) => { // 一开始的时候是不设值的,所以,要在外面做一套observe var childObj = observe(vm._data[key], cb) Object.defineProperty(obj, key, { get() { return vm._data[key] }, set(newVal) { if (vm._data[key] === newVal) { return } // 如果值有变化的话,做一些操作 vm._data[key] = newVal // 执行回调 cb() // 如果set进来的值为复杂类型,再递归它,加上set/get childObj = observe(newVal) } }) } var Observer = (obj, cb) => { Object.keys(obj).forEach((key) =>{ defineReactive(obj, key, cb) }) } var observe = (value, cb) => { // 判断是否为object类型,是就继续执行Observer if (!value || typeof value !== 'object') { return } Observer(value, cb) } vm.$watch = (name, func) => { // 回调函数 vm.callback[name] = func // 设置data defineReactive(vm.$data, name, func) } // 绑定a,a若变化则执行回调方法 var va = {a:{c: 'c'}, b:{c: 'c'}} vm._data.va = {a:{c: 'c'}, b:{c: 'c'}} vm.$watch('va', () => {console.log('又成功被监听啦')}) vm.$data.va.a = 1

再执行一次以上代码,发现内部的a属性也被监听到了,而且属性值变化的时候执行了我们事先定义好的回调函数~嘻嘻嘻~

虽然实现了$watch的基本功能,但是和vue的源码还是有一定的距离,特别是一些扁平化和模块化的思想需要涉及到一些设计模式,其实我们在看源码的时候,常常是逆着作者的思维走的,功能从简单到复杂往往涉及到代码的模块化和解耦,使得代码非常地分散,读起来晦涩难懂,自己动手,从小功能代码块实现,然后结合源码,对比思路,慢慢丰富,也不失为一种学习源码的方式~

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

转载注明出处:https://www.heiqu.com/wwjpff.html