Vue $set 源码解析(保证你也能看懂)

简介: 说明这个key本来就在对象上面已经定义过了的,直接修改值就可以了,可以自动触发响应

首先我们看文档有这个例子


image.png


下面是vue $set部分源码


if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn('Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}')
  }
  // 数组
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  // 对象
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  if (target._isVue || (ob && ob.vmCount)) {
    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) {
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()


我们先看第一块


if (process.env.NODE_ENV !== 'production' && (isUndef(target) || isPrimitive(target)) ) { warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)


我们先看第一段代码 isUndef和isPrimitive方法,从名字就可以看出,isUndef是判断target是不是等于undefined或者null。isPrimitive是判断target的数据类型是不是string、number、symbol、boolean中的一种。所以这里的意思是如果当前环境不是生产环境并且 isUndef(target) || isPrimitive(target) 为真的时候,那么就抛出错误警告。


//----------------------------------


if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }


接着我们看第二段


isArray 判断是不是数组,并且key的值是有效的数组索引。


然后将target数组的长度设置为target.length和key中的最大值,为了防止我们传入key下标超过数组长度导致报错。


尤玉溪重写了vue 的原型 arrayMethods 里面监听了七个方法 他文档上有提到


这里使用splice是arrayMethods提供的7个方法中的一种 来做到替换数组的数据


//-------------------------------------


if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
 }


我们来看第三段


他判断了这个key是不是当前对象的key 和 这个key 不是object原型的key


说明这个key本来就在对象上面已经定义过了的,直接修改值就可以了,可以自动触发响应


//------------------------------

const ob = (target: any).__ob__
  if (target._isVue || (ob && ob.vmCount)) {
    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) {
    target[key] = val
    return val
  }


我们来看第四段


我们可以看到 他给对象添加了一个__obj__属性如果一个对象有这个__ob__属性,那么就说明这个对象是响应式对象,我们修改对象已有属性的时候就会触发页面渲染


if (!ob)为真说明当前的target对象不是响应式对象,不需要响应,那么直接赋值返回即可


defineReactive(ob.value, key, val)
 ob.dep.notify()
  return val


最后一段


这里才是vue.set()真正处理对象的地方。defineReactive(ob.value, key, val)的意思是给新加的属性添加依赖,以后再直接修改这个新的属性的时候就会触发页面渲染。 ob.dep.notify()这句代码的意思是触发当前的依赖(这里的依赖依然可以理解成渲染函数),所以页面就会进行重新渲染。

目录
相关文章
|
2天前
|
缓存 Java 开发者
10个点介绍SpringBoot3工作流程与核心组件源码解析
Spring Boot 是Java开发中100%会使用到的框架,开发者不仅要熟练使用,对其中的核心源码也要了解,正所谓知其然知其所以然,V 哥建议小伙伴们在学习的过程中,一定要去研读一下源码,这有助于你在开发中游刃有余。欢迎一起交流学习心得,一起成长。
|
3天前
|
消息中间件 缓存 前端开发
Netty消息编码及发送源码解析
Netty消息编码及发送源码解析
6 0
|
5天前
|
JavaScript 前端开发 开发者
深入比较Input、Change和Blur事件:Vue与React中的行为差异解析
深入比较Input、Change和Blur事件:Vue与React中的行为差异解析
|
6天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
15天前
yolo-world 源码解析(六)(2)
yolo-world 源码解析(六)
45 0
|
15天前
yolo-world 源码解析(六)(1)
yolo-world 源码解析(六)
44 0
|
15天前
yolo-world 源码解析(五)(4)
yolo-world 源码解析(五)
48 0
|
15天前
yolo-world 源码解析(五)(1)
yolo-world 源码解析(五)
61 0
|
15天前
yolo-world 源码解析(二)(2)
yolo-world 源码解析(二)
58 0

推荐镜像

更多