由於Vue2.6.*之前偵測數據變化都是經過Object.defineProperty實現,ES6以前都沒法提供元編程能力,因此沒法偵測對象的增長和刪除屬性,這個時候須要單獨對其進行處理。vue
set方法的做用是在object或者Array上設置一個屬性, 在Vue的原型上添加方法Vue.prototype.$set = set, set方法具體實現爲:react
function set (target, key, val) {
if (isUndef(target) || isPrimitive(target)
) {
warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target))));
}
// 對數組,直接添加, 觸發前面講到的splice攔截器
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
return val
}
// key已經存在於target中,已經被偵測了變化,就能夠發送依賴通知
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val
}
// 經過獲取ob來判斷target是不是響應式的
var ob = (target).__ob__;
// 經過_isVue的屬性來判斷target是不是vue的實例
if (target._isVue || (ob && ob.vmCount)) {
warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.'
);
return val
}
// 不存在__ob__屬性就不作處理
if (!ob) {
target[key] = val;
return val
}
// 轉化爲getter/setter形式,並向target的依賴通知變化
defineReactive$$1(ob.value, key, val);
ob.dep.notify();
return val
}
複製代碼
del方法能夠刪除Object或者Array的某個屬性,在Vue原型上掛載Vue.prototype.$delete = del;編程
/**
* Delete a property and trigger change if necessary.
*/
function del (target, key) {
// 若是是數組,則直接刪除
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.splice(key, 1);
return
}
// 與set方法一致
var ob = (target).__ob__;
if (target._isVue || (ob && ob.vmCount)) {
warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.'
);
return
}
// 若是key不是target的屬性則直接返回
if (!hasOwn(target, key)) {
return
}
// 刪除屬性
delete target[key];
// 若是不是響應式數據,則返回
if (!ob) {
return
}
// 爲響應式數據的話,則通知依賴更新
ob.dep.notify();
}
複製代碼
這部分介紹了偵測數據的API,computed的實現原理在後面的初始化過程再介紹。數組