上一篇主要讲了Object类型的变化检测,为什么要讲Array类型呢?例如:this.array.push('ntyang'),请想一想,Object类型的变化检测是通过Object.defineProperty方法的getter/setter实现的,但是使用Array.prototype.push来更改数组不会触发getter/setter。那么Array类型的数据是如何实现变化检测的呢?接下来我跟大家说说1.你怎么知道发生了什么变化?上面的push方法是原型链上的一个方法。既然数组没有类似Object.defineProperty的方法,那我们换个角度想一想。可以用数组的原型链方法吗?作为切入点。用拦截器覆盖Array.prototype,然后我们每次使用数组原型方法时,实际上是执行拦截器中的方法,然后在拦截器中使用原来的Array.prototype方法。这样我们就可以在拦截器中监听Array的变化了。Array原型中有七个方法可以改变自己:push、pop、shift、unshift、splice、sort、reverse=['push','pop','shift','unshift','splice','sort','reverse']methodsToPatch.forEach(method=>{constoriginal=arrayProto[method]def(arrayMethods,方法,functionmutator(){letargs=[],len=arguments.length;while(len--)args[len]=arguments[len];returnoriginal.apply(this,args)})})functiondef(对象、键、值、可枚举e){Object.defineProperty(obj,key,{value:val,enumerable:!!enumerable,writable:true,configurable:true});}我们使用变量arrayPrototype来保存Array.prototype,它的所有功能都有。然后在arrayMethods中使用Object.defineProperty来封装这七个方法。如果我们使用show操作,使用arrayMethods覆盖Array.prototype,那么当我们使用push等方法时,实际上调用的是arrayMethods.push,也就是mutator函数。而mutator函数最终会执行数组的native方法。所以我们可以在mutator函数中做一些事情,比如发送通知。那么如何覆盖Array.prototype呢?2、覆盖Array.prototype使拦截器生效Array.prototype必须要覆盖。但是如果直接覆盖,会污染全局Array。我只想拦截那些响应数据。对了,大家有没有想到上一章的观察者呢?functionObserver(value){this.value=valueif(!Array.isArray(value)){this.walk(value)}else{value.__proto__=arrayMethods//New}}如果当前值为Array类型,直接赋值给它的隐式原型__proto__,但是鉴于目前浏览器对ES6的支持,我们需要处理无法使用__proto__的情况。Vue的处理也简单直接。既然你不能操作你的原型,你可以直接操作它。毕竟只要你有对应的方法,就不会去原型里再找,也就是把arrayMethods中的方法设置到数组中。修改Observe:consthasProto='__proto__'in{}constarrayKeys=Object.getOwnPropertyNames(arrayMethods);functionObserver(value){this.value=valueif(!Array.isArray(value)){this.walk(value)}else{//newif(hasProto){protoAugment(value,arrayMethods)}else{copyAugment(value,arrayMethods,arrayKeys)}}}functionprotoAugment(target,src){target.__proto__=src}functioncopyAugment(target,src,keys){for(leti=0,l=keys.length;i
