Vue源码解析之数据响应系统的使用(14)


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

这个if条件的意思是该属性已经在target对象上有定义了,那么只要重新设置它的值就行了。因为在纯对象中,已经存在的属性就是响应式的了。

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._isVue
拥有_isVue属性说明这是一个Vue实例‘

(ob && ob.vmCount)
ob就是target.__ob__,ob.vmCount也就是target.__ob__.vmCount。来看一下这段代码:

export function observe (value: any, asRootData: ?boolean): Observer | void {
 if (asRootData && ob) {
  ob.vmCount++
 }
}

asRootData表示是否是根数据对象。什么是根数据对象呢?看一下哪里调用observe函数的时候传递了第二个参数:

function initData (vm: Component) {
 ...

 // observe data
 observe(data, true /* asRootData */)
}

在initData中调用observe的时候传递了第二个参数为true,那根数据对象也就是data。也就是说当使用 Vue.set/$set 函数为根数据对象添加属性时,是不被允许的。

所以当target是Vue实例或者是根数据对象时,在非生产环境会打印警告信息。

if (!ob) {
  target[key] = val
  return val
}

当!ob为true时,说明不存在__ob__属性,那target也就不是响应式的,直接变更属性值就行。

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

这里就是给对象添加新的属性,并保证新添加的属性是响应式的。

ob.dep.notify()触发响应。

del

看完了set,再来看delete操作。

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

这个if判断跟set函数的一样。如果target是undefined、null或者原始类型值,在非生产环境下打印警告信息。

if (Array.isArray(target) && isValidArrayIndex(key)) {
  target.splice(key, 1)
  return
}

当target是数组类型并且key是有效的数组索引值时,也是使用splice来进行删除操作,因为该变异方法可以触发拦截操作。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/19.html