前言:
如今姐妹们对“vue重写数组的方法有哪些”都比较珍视,姐妹们都需要剖析一些“vue重写数组的方法有哪些”的相关内容。那么小编也在网络上网罗了一些对于“vue重写数组的方法有哪些””的相关文章,希望各位老铁们能喜欢,看官们一起来了解一下吧!欢迎来到我的《从源码中学Vue》专题系列文章,更多精彩内容持续更新中,欢迎关注 :)
上一章节我大概分析了下在Vue中的 Watcher、Observer、Dep三者的关系,以及如何检测数据变化去更新视图的,以及通过源码分析了vue在初始化的时候是如何响应模板数据。
本章目标Object.defineProperty存在的问题为什么在我们操作数组的时候可以实现视图更新vue中数组劫持仍然存在的问题Object.defineProperty存在的问题
我们都知道,在Vue2.x中,内部实现的数据响应是通过Object.defineProperty来实现的,其实这个API是存在一些问题的。
比如,它不能兼听到数组的变化,什么意思呢?我来举个例子。
我通过Object.defineProperty定义了一个简单的方法,当我们的key为数组的时候,我们直接通过obj.list.push修改数组的时候,可以看到,我们的set方法并没有被触发。
我们再来通过vue来看下我们修改list的时候会发生什么?
可以看到,在vue中,我们对data下的list添加元素的时候,视图被更新了,也就是说,vue中操作数组的时候会发生数据响应。
结论:原生的Object.defineProperty不能劫持数组push等操作,但是vue却可以?
为什么在我们操作数组的时候可以实现视图更新
那么说明Vue内部一定做了一些兼容处理!
带着这个问题,跟我去源码中找找答案吧!!
那么在数据劫持的目录下很容易找到一个array.js的文件,我们打开它看看
文件目录:node_modules\vue\src\core\observer\array.js
它长这样!
先不用细看,看到
这一坨代码,我们就知道,vue针对这些方法做了处理。
那好,我们接下来具体分析下vue具体做了什么?
我们将原生的Array上的原型复制出来存储到了arrayMethods变量中。之所以要复制一个原型对象出来,是不能响应原生的数组的特性。
这有一个def方法,我们去找下它的定义。
目录:node_modules\vue\src\core\util\lang.js
它就是给一个Object对象添加Object.defineProperty,然后主要看第二个参数。value,通过调用我们知道,我们传入的实参是一个function 。
什么意思呢,这里我们就能够兼听到当数组的原生方法被触发后的回调。我再举个例子
这个示例中,我兼听了原生数组的push方法,当有push操作的时候,可以触发一个回调函数。
那么到这里,相信vue的数组响应原理应该就明白了吧。
到这里还没完,我们接着往下看
我圈出来的是为了实现数组原生的方法的执行。这里面的this就是指向的我们的要兼听的数据对象
在这个方法的最后,源码调用了ob.dep.notify()方法,那么这个ob是怎么来的呢?
const ob = this.__ob__
这个对象我们可以在Observer类的中找到。
我们给value定义了一个__ob__的属性,然后赋值为this,这里面的this指向的是Observer对象。所以我们在最后可以调用ob.dep.notify()方法。
最后再来看这一坨代码
定义了一个inserted变量,它表示的是是否为添加。我们知道,给数组添加元素的方法有三个,push,unshift,splice。然后调用Observer兼听数组的observeArray方法。
splice这个方法当有第三参数的时候,可以视了给数组添加项。
思考一下,为什么要兼听数组的添加的方法呢?
其实前面也有提到过。比如,我们添加数组的项可能为一个对象,或者数组,如果这是些那么我们的Observer将要继续兼听这个对象,给这个对象添加get和set方法。
举个例子
当我们给数组添加成一个对象的时候,vue这时候也会劫持对象,我们可以看到对象的a已经被设置了get和set。
vue中数组劫持仍然存在的问题
在vue中,有一种情况下数组是不能被劫持的,那就是当我们手动通过索引改变数组的某一项的时候,不会触发视图的更新。比如这样:
这个解决办法就是重新给list赋值 ,我们知道数组的concat和slice方法都可以返回一个全新的数组。我们可以这样做。
vm.list = vm.list.concat([]); 或者vm.list = vm.list.slice();
到这里,Vue劫持数组的原理基本上就分享完了。
总结:原生的 Object.defineProperty并不能劫持数组的变化。vue是通过重写了数组的Array原型上的方法,实现了数据的劫持当我们通过索引去修改数组的时候,可以调用数组的slice和concat方法来手动实现视图更新Object.defineProperty可以实现JS内部函数的劫持。
这里是畅哥聊技术 《从源码中学Vue》系列文章,更多精彩内容持续更新中,敬请期待。
未完待续。。。
标签: #vue重写数组的方法有哪些