vue2源码学习-Array七种原型方法hack

it2023-09-18  64

在Vue2中如果直接通过下标修改数组的值,不会触发视图的更新,只能通过push、pop、shift、unshift、splice、sort和reverse7种方法改变才会触发响应式更新。尤大的解释是直接监听数组的下标会带来性能损耗,所以通过hack的方式覆写这些编译方法。

其实现原理如下,每行代码都进行了注释:

// 源码目录:src/core/array.js // 获取工具方法def,定义对象的数据描述符 import { def } from '../util/index' // 获得Array的原型对象 const arrayProto = Array.prototype // 继承Array的原型,后面defineProperty修改属性描述符,实现原型法的hack export const arrayMethods = Object.create(arrayProto) // hack的7种会修改数组元素的方法 const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] // 通过修改数据描述符,拦截这7种方法,并派发更新 methodsToPatch.forEach(function (method) { // 暂存初始Array的原型方法 const original = arrayProto[method] // 修改数据描述符 def(arrayMethods, method, function mutator (...args) { // 调用原生方法,存储结果 const result = original.apply(this, args) // 获取当前Vue实例的Observer const ob = this.__ob__ // 保存插入的数据,需要转换成响应式数据 let inserted // push、unshift、splice三种方法会插入,分别取得其对应的插入值 switch (method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } // 将插入的数据也转换成响应式 if (inserted) ob.observeArray(inserted) // 派发更新 // 每个Observer都管理一个依赖收集器Dep,当触发setter时,就是通过Dep派发更新,让Watcher更新视图。 ob.dep.notify() // 返回执行结果 return result }) })

其中__ob__获取Observer实例,我们查看observer的源码

// 源码目录:src/observer/index.js // 观察数组 observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { // 使数组元素变为响应式数据 observe(items[i]) } }
最新回复(0)