Vue知识回顾与总结【二】
文章目录
第二章 Vue如何实现数组的变化侦测
写在前面
今天是一个特殊的日子,在此向所有逆行者致敬,向所有牺牲者致哀!!!
Vue数组的变化侦测为什么和对象不同?
首先我们思考这样一个问题,为什么在Vue中数组的变化侦测和对象不同?因为我们可以通过Array原型的方式操作数据,所以Object的getter和setter方式就无法侦测到数组元素的变化。
Array中可以改变数组的方法有以下7个:
push
向数组尾部加入单个或多个元素pop
弹出数组尾部的最后一个元素shift
弹出数组首部的第一个元素unshift
向数组首部加入元素splice
截切数组sort
数组排序reverse
简单的数组元素反转
Vue的办法:利用拦截器覆盖Array.prototype
利用拦截器覆盖Aray.prototype,即重写Array的原型方法。当我们再Vue中调用上述7个方法时,其实是在调用Vue的拦截器方法。这样就可以在拦截器内部实现依赖管理的相关操作和逻辑。
Vue 数组中的依赖管理
数组仍然是在getter上收集依赖,而依赖的触发则是放到拦截器中进行。数组和对象不同的地方在于依赖存放的位置不同,Vue把数组的依赖放在了Observer实例中
其目的是保证拦截器和getter都能访问到依赖。这样就能通过ob.dep.notify()
去通知依赖watcher数据发生了变化。
- 备注:ob:Observer实例;dep:Dep实例;watcher:Watcher实例
无法侦测的情况
Array的变化侦测通过拦截原型的方法实现,因而有些操作数组的方法是无法实现变化侦测的,比如:
- 通过数据索引改变数组元素:如this.arr[1] = 111;
- 通过length改变数组的长度:如thia.arr.length = 10;
- 上述两种方式我们在开发时应当尽量避免,除非操作的是非响应式数据。此外可以通过全局API
this.$set()和this.$delete()
解决问题1.
对_proto_的处理
为了不污染全局Array.prototype,希望Observer中只针对需要侦测数据变化的数组使用_proto_来覆盖原型方法,但是_proto_
属性在ES6之前不是所有浏览器都支持,针对不支持_proto_
属性的浏览器采用比较“暴力”的方式,直接循环拦截器,将拦截器方法设置到数组身上来拦截Array.prototype上的原生方法。