vue源碼系列03_數組劫持

vue源碼系列03_數組劫持

重寫方法

  1. 由於是數組的話並不會對索引進行觀測,因爲會導致性能問題,因爲前段開發中很少去操作索引 咱用的更多是 push shift unshitf
  2. 我們在Observer類開頭使用 observerArray() 來對數組中的每一個數據進行監控
  3. 所以我們可以採用給數組方法上添加一個代理(也就是我們在執行原本數組的方法之前,我們預先進行一些操作)
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])
    }
}
  1. 給每個監控過的對象添加一個 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;
    }
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章