数组的劫持
> 1. 数组劫持的思路
>
> 对于数组劫持的目标是实现数组的响应式:
>
> - 在Vue
中,我们很少会使用索引进行操作数组,并且认为有七个方法能够改变数组:
>
> push
、pop
、splice
、unshift
、reverse
,sort
。所以,需要对七个方法进行特殊处理,是他们能够劫持到数组的数据变化,就能够实现数组的响应式。
>
> 因此,要单独处理,在Observer
初始化时会walk
遍历属性实现递归;所以就需要将数组响应式的处理逻辑单独出来,重写这个七个方法:
>
> javascript > import { arrayMethods } from "./array"; > > class Observer { > constructor(value) { > if(isArray(value)){ > // 对数组类型进行单独处理:重写 7 个变异方法 > }else{ > this.walk(value); > } > } > } >
>
> 2. 数组的重写的注意
>
> 数组重写不能影响非响应式数组。
>
> 所以,对响应式数据中数组的这七个方法进行拦截:优先从链上查找到并使用重写方法啊,其他方法依然走原生逻辑。
>
> javascript > // 希望重写数组中的部分方法 > let oldArrayProto = Array.prototype; > > // newArrayProto.__proto__ = oldArrayProto > export let newArrayProto = Object.create(oldArrayProto); > > // 找到所有的变异方法 > let methods = ["push", "pop", "shift", "unshift", "reverse", "sort", "splice"]; > > methods.forEach((method) => { > // arr.push(1,2,3) > newArrayProto[method] = function (...args) { > // 重写了方法 > // push.call(arr) > const result = oldArrayProto[method].call(this, ...args); // 内部调用原来的方法,函数的劫持,切片编程 > > // 新增的数据进行劫持 > let inserted; > // 后面的 > let ob = this.__ob__; > switch (method) { > case "push": > inserted = args; > break; > case "unshift": > inserted = args; > break; > case "splice": > inserted = args.slice(2); > break; > default: > break; > } > if (inserted) { > // 对新增的内容进行观测 > ob.observeArray(inserted); > } > // 后面的 > ob.dep.notify(); > return result; > }; > }); > >
>
> - 首先,拿到数组的所有原生方法oldArrayProto
,通过Object.create
原型继承放到arrayMethods
原型链上,相当于将原生方法向后移动了一层。
> - 当value
为数组类型时,修改数组的原型链为arrayMethods
;此时,原本在value.__propto__
上原生方法。
> - 在arrayMrthods
进行处理,在第一层对7个变异方法进行重写,利用js
原型链查找机制,就实现了对原生方法的拦截。