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;
    }
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章