目录
- Vue中对Array和Object追踪方式的不同之处?
- 拦截原型
- 创建拦截器
- 如何拦截
- 响应式具体实现
- 依赖收集到哪里?
- 如何收集?
- 通知依赖
- 数组子集和新增元素的追踪
- 数组子集转换成响应式
- 新增元素转换成响应式
- Array中的问题
Vue中对Array和Object追踪方式的不同之处?
Object通过setter改变属性的值,所以我们利用getter时发送依赖收集,在setter时触发依赖更新,而且Vue将数据转换成响应式数据是在数据初始化时,对Object中之后的属性新增和删除操作,无法做到自动更新,而是通过vm. s e t 和 v m . set和vm. set和vm.delete手动转换成响应式,并立即发出更新通知。
但是,一般在对数组的操作中,可以改变数组自身内容的方法有push、pop、shift、unshift、splice、sort、reverse七个。当我们给一个数组类型的属性赋值时,属性的setter函数会触发,从而通知更新。但是在使用push等一系列操作方法时,由于ES6之前,JS没有元编程能力,没有提供可以拦截原型方法的能力,所以,我们思考,如果能在用户使用这些方法操作数组时得到通知,那就达到了追踪的目的。
拦截原型
如何做到在操作这些原型方法时能得到通知呢?
对!就是拦截原型。
基本原理:用一个拦截器覆盖Array.prototype, 每当使用原型上的方法操作数组时,实际上执行的都是拦截器提供的方法,在拦截器中除了调用原生的方法操作数组外,还可以干点别的事,比如:通知依赖更新!
创建拦截器
- 编写拦截器
- 定义需要拦截的原型方法集合
methodsToPatch
var arrayProto = Array.prototype;
// 创建一个新的空对象arrayMethods,并将原型指向Array.prototype
var arrayMethods = Object.create(arrayProto);
var methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
- 方法重写
methodsToPatch.forEach(function (method) {
// 缓存原始方法
var original = arrayProto[method];
// 方法重写,屏蔽了Array.prototype上的方法,同时内部调用Array.prototype上的原始方法
def(arrayMethods, method, function mutator (...args) {
var result = original.apply(this, args);
// 占位符D1 :这里可以做些事:比如通知依赖更新...
return result
});
});
function def (obj, key, val, enumerable) {
Object.defineProperty(obj, key,