重寫方法
- 由於是數組的話並不會對索引進行觀測,因爲會導致性能問題,因爲前段開發中很少去操作索引 咱用的更多是 push shift unshitf
- 我們在Observer類開頭使用 observerArray() 來對數組中的每一個數據進行監控
- 所以我們可以採用給數組方法上添加一個代理(也就是我們在執行原本數組的方法之前,我們預先進行一些操作)
if (Array.isArray(value)){
value.__proto__ = arrayMethods; // 給數組的原型上添加數組的方法,函數劫持
// 如果數組裏放的是對象,我再監控
def(value,'__ob__',this); // 添加__ob__ 屬性,我們在調用時可以獲取到 this
this.observerArray(value);
} else {
this.walk(value)
}
observerArray(value) {
for (let i = 0; i < value.length; i++) {
observe(value[i])
}
}
- 給每個監控過的對象添加一個 ob 屬性,方便我們在其他地方調用它的方法
在util中添加該方法,並在observer/index.js導入
export function def(data, key, value) {
Object.defineProperty(data, key, {
enumerable: false,
configurable: false,
value
})
}
array.js
爲了讓源碼更容易閱讀,我們在observer文件夾下創建該模塊,專門處理數組響應式的問題
說到底就是原型鏈查找的問題,會向上查找,先查找我重寫的,沒有重寫的會繼續向上查找
- 流程:
- 先獲取數組原型上的方法 oldArrayMethods
- value.proto = arrayMethods 讓當前數組的原型用 arrayMethods
- arrayMethods.proto = oldArrayMethods 向arrayMethods的原型上加上原來數組的方法
// 我要重寫數組的方法 7個 push shift unshitf pop reverse sort splice 會導致數組本身發生變化
// 除了 slice()
let oldArrayMethods = Array.prototype;
// value.__proto__ = arrayMethods 原型鏈查找的問題,會向上查找,先查找我重寫的,沒有重寫的會繼續向上查找
// arrayMethods.__proto__ = oldArrayMethods
export const arrayMethods = Object.create(oldArrayMethods);
const methods = [
'push',
'shift',
'unshift',
'pop',
'sort',
'splice',
'reverse'
]
methods.forEach(method=>{
arrayMethods[method] = function(...args){ // AOP 切片編程
const result = oldArrayMethods[method].apply(this,args); //調用原生的數組方法
// push unshift 添加的元素可能還是一個對象
let inserted; // 用戶插入的元素
let ob = this.__ob__;
switch(method){
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice': // 3 個 新增的屬性 splice 有刪除 新增的功能
inserted = args.slice(2)
default:
break;
}
if(inserted) ob.observerArray(inserted); // 將新增屬性繼續觀測
// 這裏需要通知其他人數據的改變
return result;
}
})