vue中如何检测数组的变化

我们知道,Object.defineProperty不能检测数组的操作,因此需要拦截数组的操作(push, unshift, splice等)并重写他们,使之可以对新操作的数据进行检测。

拦截数组方法的思路:
  1. 缓存数组的操作方法,直接缓存Array.prototype就行
  2. 使用一个代理数组,重写代理数组的操作方法,代理数组的原型指向Array.prototype
  3. 实例继承代理数组
代码实现
const arrayProto = Array.prototype  // step1
const arrayMethods = Object.create(arrayProto) // step2

const methodsToPath = ['push','pop','shift']

methodsToPath.forEach(function(method){
  const original = arrayProto[method]  // 缓存方法
  def(arrayMethods,method,function mutator(...args){
    // 执行缓存的方法以保证重新的方法与数组原方法功能一致
    const result = original.apply(this,args) 
    //无论是数组还是对象都会被定义一个__ob__属性,
    // 并且__ob__,dep手机了所有该对象(或数组)的依赖(观察者)
    const ob = this._ob__
    //省略了部分代码
     ......
     //notify change
     ob.dep.notify()
    return result
  })  
})

上述代码,通过重写arrayMethods上的数组操作方法,实现了在操作数组时,通知依赖更新。
你以为这就完成了吗? 不。还需要补充一点。

操作数组之后,数组发生了什么变化?
答: 数组增加了元素删除了元素, 变更了元素顺序(还有可能是元素被替换了,不过替换可以理解为先删除后增加两个动作)。
重点来看增加了元素, 即push, unshift, splice这三个方法,为什么要重点关注呢? 因为新增加的元素是非响应式的,所以需要获取这些元素,并将其变为响应式数据才行。

// 上面所省略的那部分代码
...
const ob = value.__proto__
let inserted // 用来获取新增的元素
switch(method){
  case 'push':
  case 'unshift':
     inserted = args; break;
  case 'splice':
     inserted = args.slice(2); break
}
if(inserted) ob.observeArray(inserted)
//notify change
ob.dep.notify()
...
splice()方法向/从数组中 添加/删除项目,然后返回被删除的项目,该方法会改变原始数组
arrayObj.splice(index, homany, item1, ..., itemX)
1. index: 必需,添加或删除项目的位置索引
2. howmany: 必需,要删除的项目数量,如设置为0,表示不删除
3. item1,...itemX: 可选,向数组中添加的新项目
// 上述 inserted = args.slice(2) 就是取 第三项之后的所有项
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值