前面的話
前端日問,鞏固基礎,不打烊!!!
解答
搞懂set原理要先搞懂響應式原理,如果不動響應式原理,可以先看小柒前面的文章。
- 受現代 JavaScript 的限制 (而且 Object.observe 也已經被廢棄),Vue 無法檢測到對象屬性的添加或刪除。
- 由於 Vue 會在初始化實例時對屬性執行 getter/setter 轉化,所以屬性必須在 data 對象上存在才能讓 Vue 將它轉換爲響應式的。
- 對於已經創建的實例,Vue 不允許動態添加根級別的響應式屬性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套對象添加響應式屬性。
- 那麼 Vue 內部是如何解決對象新增屬性不能響應的問題的呢?
export function set(target: Array<any> | Object, key: any, val: any): any {
// target 爲數組
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 修改數組的長度, 避免索引>數組長度導致splice()執行有誤
target.length = Math.max(target.length, key);
// 利用數組的splice變異方法觸發響應式
target.splice(key, 1, val);
return val;
}
// target爲對象, key在target或者target.prototype上 且必須不能在 Object.prototype 上,直接賦值
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val;
}
// 以上都不成立, 即開始給target創建一個全新的屬性
// 獲取Observer實例
const ob = (target: any).__ob__;
// target 本身就不是響應式數據, 直接賦值
if (!ob) {
target[key] = val;
return val;
}
// 進行響應式處理
defineReactive(ob.value, key, val);
ob.dep.notify();
return val;
}
- 如果目標是數組,使用 vue 實現的變異方法 splice 實現響應式
- 如果目標是對象,判斷屬性存在,即爲響應式,直接賦值
- 如果 target 本身就不是響應式,直接賦值
- 如果屬性不是響應式,則調用 defineReactive 方法進行響應式處理