这是我参与更文挑战的第8天,活动详情查看: 更文挑战
一,前言
上篇,通过 Vue Demo 的断点调试,对当前版本数据劫持、数据代理进行了简单的流程梳理
同时,对照 Vue2.x 提供的功能,分析了当前版本数据观测的问题和不足
本篇,数组的深层观测
二,抛出问题
let vm = new Vue({
el: '#app',
data() {
return {
arr: [
[1,2,3],// 数组中的数组,不会被深层观测
[4,5,6],
[7,8,9],
]
}
}
})
vm.arr[0].push(0) // 对数组中的数组执行 push 操作
当前版本源码,处理数组类型的数据时,通过重写当前数组的原型方法,从而实现数组的数据劫持;
但是,如果数组中还嵌套着数组,当前版本对于嵌套数组是不会进行深层劫持的;
三,数组深层劫持的思路
目前仅对最外层数组进行了原型方法的重写,想要对数组内嵌套的数组实现数据观测能力,就需要对数组内部的数据继续进行递归处理;
四,数组深层劫持的实现
通过以上分析,实现数组的深层劫持,需要处理两种情况:
- 数组中嵌套数组(数组套数组)
- 数组中嵌套对象(数组套对象)
在 Observer 类中,创建 observeArray 方法,对数组进行深层观测:
// src/observe/index.js
class Observer {
constructor(value) {
if (isArray(value)) {
value.__proto__ = arrayMethods;
this.observeArray(value); // 对数组数据类型进行深层观测
} else {
this.walk(value);
}
}
/**
* 遍历数组,对数组中的对象进行递归观测
* 1)[[]] 数组套数组
* 2)[{}] 数组套对象
* @param {*} data
*/
observeArray(data) {
console.log("进入 observeArray, 对数组类型进行观测,当前数组: "+ JSON.stringify(data))
// 对数组中的每一项调用 observe 方法,继续进行深层观测处理;
// observe 方法内:如果是对象类型,继续 new Observer 进行递归处理
data.forEach(item => observe(item))
}
}
export function observe(value) {
// 1,经过前面的处理 value 一定是对象,如果此时不是对象说明有问题,直接 return 掉
// 注意:数组也是对象,但 value 不能是数组;(在 vue 中,data 不能是数组)
if (!isObject(value)) {
console.log("observe 方法结束: value不为对象, 当前 value: " + value)
return;
}
// 2,观测 value 对象,实现数据响应式
return new Observer(value);
}
observeArray 方法:
- 递归遍历数组,对数组的每一项调用
observe方法,继续进行深层观测处理: - 如果数组中是对象,则会继续观测;如果数组中时普通值,则不会继续观测;所以,数组中如果的引用类型是响应式的
这样,数组中的数组 [ [] ]、数组中的对象[ {} ],两种情况就都实现了数据的深层观测;
五,注意事项与性能问题
1,注意事项
对于数组类型,目前仅对重写了部分原型方法,并未对数组的每一项进行数据劫持;
- 数组中的普通值,不能被观测;(仅重写数组方法,递归中对值类型不再处理)
- 数组中的引用类型,能够被观测;(observe 实现对象类型深层观测)
举例分析:
1,当vm.arr[0]为普通值时:
vm.arr[0] = 100操作数组索引,由于没对数组索引观测,所以不会触发视图更新;
2,当vm.arr[0]为对象时:
vm.arr[0].a = 1修改对象属性,由于对象已具备深层观测,所以会触发视图更新;
2,性能问题
在 Vue2 中,需要对数组的原型方法进行重写,并且当数组中嵌套着数组时,还需要进行递归重写;因此,在实际应用中当数组的层次过深时,就容易产生性能问题;
Vue2 对数据的处理,涉及到了属性、方法以及数组原型链的重写,所以,会有性能问题;
六,结尾
本篇,介绍了数组的深层观测实现,核心几个点如下:
- 在之前对数组类型的处理中,仅对当前数组进行了部分原型方法重写操作,当通过变异方法操作数组时,相当于实现了数组的单层数据劫持能力;
- 通过
observeArray方法继续处理数组类型,对数组中每一项调用observe进行递归观测,实现了数组中嵌套结构的劫持:数组嵌套数组、数组嵌套对象;
注意:在 observe方法仅处理了对象类型,所以数组中的值类型是不会被观测的;
目前,数据观测剩余问题:
- 实现对象中新增对象的观测(深层)
- 实现对象中新增属性的观测
- 实现数组中新增对象的观测(深层)- 原型方法重写
下一篇,对象中新增对象的深层观测
维护日志
- 20230111:重新梳理文章内容,调整了文章的目录结构、排版、内容中的代码高亮,对大量文字描述进行优化并添加截图;