关于this.$set的源码解析

548 阅读1分钟

1.关于数组

eg: arr = [1,2,3]
this.$set(this.arr,4, 20) // arr [1,2,3,null,20]
此时可以得到结论:this.$set可以修改数组并触发更新

2.关于对象

eg: obj = { name: '张三'}
this.obj.id = 4 // 页面上此时是不会刷新的
this.$set(this.obj, 'id' , 5) //页面上会刷新,显示id为5
setTimeout(()=>{ this.obj.id = 8 },5000) //页面上5s后会显示8
可以得到结论:通过this.set修改的对象属性会加入监听。下次修改时无需再次通过this.set修改的对象属性会加入监听。下次修改时无需再次通过this.set触发更新

3.源码解析

  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() //通知更新
  return val
}