mc-congxueda

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
统计
 

源码如下:

复制代码
复制代码
export function set (target: Array<any> | Object, key: any, val: any): any {
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
  }  // 判断目标值是否为数组,并且key值是否为有效的数组索引
  if (Array.isArray(target) && isValidArrayIndex(key)) {  // 对比数组的key值和数组长度,取较大值设置为数组的长度
    target.length = Math.max(target.length, key)  // 替换目标值
    target.splice(key, 1, val)
    return val
  }  // 如果目标值是对象,并且key值是目标值存在的有效key值,并且不是原型上的key值
  if (key in target && !(key in Object.prototype)) {  // 直接更改目标值
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__ // 判断目标值是否为响应式的
  if (target._isVue || (ob && ob.vmCount)) { // 如果是vue根实例,就警告
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  if (!ob) { // 如果目标值不是响应式的,那么值需要给对应的key赋值
    target[key] = val
    return val
  }  // 其他情况,目标值是响应式的,就通过Object.defineProperty进行数据监听
  defineReactive(ob.value, key, val)  // 通知更新dom操作
  ob.dep.notify()
  return val
}
复制代码

 

复制代码

大概流程就是:

  1.判断目标值是否为有效值,不是有效值直接停止

  2.判断是否为数组,并且key值是否为有效的key值

    如果是数组,就选择数组的长度和key值取较大值作为数组的新的length值,并且替换目标值

    splice方法,重写了,所以执行splice,会双向数据绑定

  3.判断目标值是否为响应式的__ob__

    如果是vue实例,直接不行

    如果不是响应式的数据,就是普通的修改对象操作

    如果是响应式数据,那就通过Object.defineProperty进行数据劫持

  4.通知dom更新

 

继续往下挖坑  https://www.qiyuandi.com/zhanzhang/zonghe/11665.html

Array的变化侦测

 

ue中数组并不是通过监听索引去实现变化侦测的,因为这样做当我们用list.push(1)向list数组中push一个1时,并不会触发get/set。而我们日常编程中会频繁使用Array原型上的方法去操作数组,所以object那种方法就不灵了。

 

也正因为如此,vue中重写了数组原型上的方法,当我们使用数组原型方法改变数组时,向依赖发送通知即可

 
 
我们回过头来看Observe类的observerArray方法,只是遍历了传进来的数组,并且递归调用observe监听子项。而再调用observerArray方法之前则将value的原型指向了arrayMethods,我们来看下arrayMethods具体是怎么实现的。
源码路径:src\core\observer\array.js
复制代码
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)

const methodsToPatch = ['push','pop','shift','unshift','splice','sort','reverse']

methodsToPatch.forEach(function (method) {
  // cache original method
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {
    const result = original.apply(this, args)
    const ob = this.__ob__
    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()
    return result
  })
})
复制代码

 

Array. prototype.splice 重写 ---observeArray 法对新增项进行变化侦测。

首先保存了Array的原型,然后创建了arrayMethods的原型指向Array的原型,因为js中只有push、pop、shift、unshift、splice、sort、reverse这七个方法会改变原数组,所以只需要重写这七个方法就可以了。然后给arrayMethods添加这七个方法。在重写的方法里调用原来的方法对数组进行操作,然后手动通知依赖进行更新即可。因为push、unshift、splice可以给数组新增项,而新增项也可能是对象或数组所以调用observeArray方法对新增项进行变化侦测。

上面我们频繁提到依赖、依赖收集、通知依赖更新,那什么是依赖呢?依赖又收集到哪里去呢?我们接着往下看。

 

 

posted on   MC~大叔  阅读(486)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
 
点击右上角即可分享
微信分享提示