vue.$set实现原理

上源码:

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.cnblogs.com/yaxinwang/p/13827529.html