1. export function set (target: Array<any> | Object, key: any, val: any): any {
    2. // target 非法校验,只能为数组和对象这类引用类型添加新的索引值
    3. if (process.env.NODE_ENV !== 'production' &&
    4. (isUndef(target) || isPrimitive(target))
    5. ) {
    6. warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
    7. }
    8. // 如果 target 是数组,且索引是有效的索引值(非负整数)
    9. if (Array.isArray(target) && isValidArrayIndex(key)) {
    10. // 修改数组的长度,如有必要
    11. target.length = Math.max(target.length, key)
    12. // 通过 splice 来添加值,因为如果 target 本身已经具备响应式,则 splice 已被挟持过了,所以自然而然新值就会变成响应式的值
    13. target.splice(key, 1, val)
    14. return val
    15. }
    16. // https://github.com/vuejs/vue/issues/6845#issuecomment-407390645
    17. // 判断 key 是否已存在于 target 及其原型上,且不在 Object 的原型上,则仅赋值
    18. if (key in target && !(key in Object.prototype)) {
    19. target[key] = val
    20. return val
    21. }
    22. // 以下的情况则是,非数组,key 值确实之前缺省
    23. // 取出 Observer
    24. const ob = (target: any).__ob__
    25. // 如果 target 是 vue 实例,或 者target 是组件的根 data, 则提示非法报错
    26. // 之所以不能在根 data 上,因为根 data 无法收集依赖
    27. if (target._isVue || (ob && ob.vmCount)) {
    28. process.env.NODE_ENV !== 'production' && warn(
    29. 'Avoid adding reactive properties to a Vue instance or its root $data ' +
    30. 'at runtime - declare it upfront in the data option.'
    31. )
    32. return val
    33. }
    34. // 如果没有监听过 target 非响应式的,则直接赋值
    35. if (!ob) {
    36. target[key] = val
    37. return val
    38. }
    39. // target 已经被监听过了,则使 key 值在其中具备响应式
    40. defineReactive(ob.value, key, val)
    41. // 通知依赖项更新
    42. ob.dep.notify()
    43. return val
    44. }