在vue中,对响应式处理的是Object.defineProperty对数据进行拦截,而这个方法并不能监听到数组内部变化,数组长度变化,数组截取变化等,所以需要对这些操作进行hack,让Vue能监听到其中变化
Vue被监听的数组的变更方法进行了包裹,所以它们也将会触发视图更新,这些被包裹的方法,包括:
- push()
- pop()
- inshift()
- shift()
- splice()
- sort()
- reverse()
那vue如何实现让这些数组方法实现实时更新的呢,下面是vue这些方法的封装
//缓存数组原型
const arrayProto = Array.prototype;
//实现arrayMethods.__proto__ === Array.protopyte
export const arrayMethods = Object.create(array.Proto);
//需要进行功能扩展的方法
const methodsToPath = [
"push",
"pop",
"shift",
"unshift",
"splice",
"sort",
"reverse"
];
methodsToPath().forEach(function(method){
//缓存原生数组方法
const original = arrayProto[method];
def(arrayMethods,method,function mutator(...args){
//执行并缓存原生数组功能
const result = original.apply(this.args);
//响应式处理
const ob = this.__ob__;
let inserted;
switch(method){
//push、unshift会新增索引,所以要手动observer
case "push":
case "unshift";
inserted = args;
break;
//splice方法,如果传入了第三个参数,也会有索引加入,也要后手动observer
case"splice":
inserted = args.slice(2);
break;
}
if (inserted)ob.observeArray(inserted);//获取插入值,并设置响应式监听
//notify change
ob.dep.notify();//通知依赖更新
//返回原生数组方法的执行结果
return result;
})
});
简单来说就是,重写了数组中的那些原生方法,首先获取到这个数组的_ob_,也就是它的OBserver对象,如果有新的值,就调用ObserverArray继续对新的值观察变化(也就是通过target__proto__ == arrayMethods来改变数组实例的型),然后手动调用notify,通知渲染watcher,执行updata