侦测数组中元素变化
侦测数组的变化类比对Object的递归处理,我们也需要监测子项的变化。
另外,数组与对象的使用需求有些不同,数组要求新增的项依然能够被监测到(想象你对一个响应式的数组push一个子数组,后面操作这个子数组时,页面没反应,就显得奇怪了!)。
首先做对子项的侦测:
export class Observer{
constructor(value){
this.value = value;
def(value, '__ob__', this);
if(Array.isArray(value)){
this.observeArray(value);
} else {
this.walk(value);
}
}
observeArray(items){
for(let i = 0, l = keys.length;i < l;i++){
observe(items[i]);
}
}
}
像这样对数组进行递归的处理就可以做到子项变成响应式的了。
侦测新增元素的变化
[
'push',
'pop',
'shift',
'unshift',
'splice',
'sorte',
'reverse'
].forEach(function(method){
const original = arrayProto[method];
def(arrayMethods, method, function mutator(...args){
const ob = this.__ob__;
let inserted;
switch(method){
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.slice(2);
break;
}
ob.dep.notify();
return original.apply(this, args);
})
})
不难发现九个方法中,可以新增元素的只有前插、后插和插入操作,捕捉响应的参数就好了。
获取的到新增元素的话就可以递归的把这些变成响应式数据了。
[
'push',
'pop',
'shift',
'unshift',
'splice',
'sorte',
'reverse'
].forEach(function(method){
const original = arrayProto[method];
def(arrayMethods, method, function mutator(...args){
const ob = this.__ob__;
let inserted;
switch(method){
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.slice(2);
break;
}
if(inserted) ob.observeArray(inserted); // 新增
ob.dep.notify();
return original.apply(this, args);
})
})
侦测数组的缺陷
由于是通过拦截原型方法完成响应,因此,对于通过[]直接修改和对length的赋值无法侦测。
this.list[0] = 2;
this.list.length = 0;