- vue中我們對數組進行push,splice,shift的一些操作時候也會觸發render-watcher。這是因為vue中對這些數組的方法進行了一些擴展,使其能夠進行數據的響應式,源碼如下:
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
// arrayMethods 就是 繼承自 Array.prototype 的數組
// 只需要讓響應式數組 繼承子 arrayMethods
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method];// 緩存之前的原型方法
def(arrayMethods, method, function mutator (...args) {// 原型的重新繼承
const result = original.apply(this, args)
const ob = this.__ob__ // 是否響應式的標志,保存了依賴收集對象deps
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted) // 進行數據響應式
// notify change
ob.dep.notify() // 手動更新變化
return result
})
})
- 但在vue中對數組的下標賦值處理時,是不會觸發視圖的更新,於是vue提供了一個靜態方法;set、del;數組是通過splice進行操作的,這里列舉一個set源碼:
export function set (target: Array<any> | Object, key: any, val: any): any {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val) // 利用擴展的splice方法進行響應式
return val
}
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = (target: any).__ob__
if (target._isVue || (ob && ob.vmCount)) {
return val
}
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value, key, val); // 讓子項響應式
ob.dep.notify(); // 手動派發更新
return val
}
- 簡化原理;
- 一個數組的原型鏈對應如:arr.proto->Array.prototype-> .proto->Object.prototype;
- 所以我們可以添加一個__proto__;arr.proto->(Object.create(Array.prototype))->Array.prototype-> .proto->Object.prototype;
let ARRAY_METHODS = [
'push',
'pop',
'shift',
'unshift',
'splice',
'reverse',
'sort'
];
let array_methods = Object.create(Array.prototype);
ARRAY_METHODS.forEach(method=>{
array_methods[method] = function(){
console.log('攔截了數組的方法',this);
let res = Array.prototype[method].apply(this,arguments);
return res;
}
});
let arr = [];
arr.__proto__ = array_methods;