vue 源码 set方法 笔记

78 阅读1分钟
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)}`)
  }
  //splice 其实已经不仅仅是原生数组的 splice 了,被重写过。新添加的属性具有了响应式
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  // 判断 key 已经存在于 target 中,则直接赋值返回,因为这样的变化是可以观测到了
  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
  }
  // 如果它不存在,则说明 target 不是一个响应式的对象,被冻结或不可枚举,则直接赋值并返回。
  if (!ob) {
    target[key] = val
    return val
  }
  //属性变响应式
  defineReactive(ob.value, key, val)
  //手动通知更新
  ob.dep.notify()
  return val
}