上源碼:
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更新