重写方法
- 由于是数组的话并不会对索引进行观测,因为会导致性能问题,因为前段开发中很少去操作索引 咱用的更多是 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;
}
})