写点什么

【Vue2.x 源码学习】第八篇 - 数组的深层劫持

用户头像
Brave
关注
发布于: 2021 年 06 月 08 日
【Vue2.x 源码学习】第八篇 - 数组的深层劫持

一,前言


上篇,通过 Vue Demo 的断点调试,对当前版本数据劫持、数据代理进行了简单的流程梳理

同时,对照 Vue2.x 提供的功能,分析了当前版本数据观测的问题和不足


本篇,数组的深层观测


二,数组深层劫持的思路

1,问题分析


let vm = new Vue({  el: '#app',  data() {    return {       arr: [        [1,2,3],// 数组中的数组,不会被深层观测        [4,5,6],      	[7,8,9],      ]     }   }})
vm.arr[0].push(0) // 对数组中的数组.push
复制代码

当前代码版本中,遇到数据类型时,会对当前数组进行原型方法的重写,实现数组的数据劫持

但是,当前代码仅对数组 7 个方法进行劫持,尚未实现劫持后的逻辑

对于数组类型中嵌套的内容(数组、对象、普通值)还并没有进行深层处理


所以,尚不支持对于数组中的内容(对象、数组、普通值)进行观测

即,以上代码片段,对数组中的数组添加内容,是不会被重写后原型方法所劫持的

2,解决方案

对数组的数据劫持操作进行递归处理,实现嵌套数组的数据劫持能力

3,性能问题


Vue2.x 中,由于需要对数组的原型方法进行递归重写,

因此,当数组层次过深时,就容易产生性能问题;(需重写属性、方法和数组的链)


三,数组深层劫持的实现

1,代码实现

通过以上分析,实现数组的深层劫持,需要处理两种情况:

  1. 数组中嵌套数组

  2. 数组中嵌套对象

// 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) { // observe方法内,如果是对象类型,继续 new Observer 进行递归处理 data.forEach(item => observe(item)) }}
复制代码

observeArray 方法:为数组中的每一项,调用 observe 进行深层观测处理

这样,数组中的数组 [ [] ]、数组中的对象 [ {} ] ,两种情况都实现了数据的深层观测

2,问题分析


由于仅重写了数组的部分原型方法,未对每一项进行数据劫持

所以,数组中的普通值,不能被观测;(仅重写数组方法,递归中对值类型不再处理)

数组中的引用类型,能够被观测;(observe 实现对象类型深层观测)


举例分析:

  1. 若 vm.arr[0] 为普通值:(仅重写数组方法,递归中对值类型不再处理)

vm.arr[0] = 100 操作数组索引,不会触发视图更新(没对数组索引观测)

  1. 若 vm.arr[0] 为对象:(observe 实现对象类型深层观测)

vm.arr[0].a = 1 修改对象属性,会触发视图更新


四,结尾


又成功水了一篇,还剩 13 篇


本篇,介绍了数组的深层观测实现,核心几个点如下:

之前对数组类型的处理中,仅对当前数组进行了部分原型方法重写操作,即仅实现了数组的单层数据劫持能力,

继续对数组进行 observe 递归观测操作;实现数组中嵌套结构的劫持,即数组嵌套数组、数组嵌套对象

注意:observe 方法对非对象不进行操作,所以数组中的值类型是不会被劫持的


目前,数据观测剩余问题:

  1. 实现对象中新增对象的观测(深层)

  2. 实现对象中新增属性的观测

  3. 实现数组中新增对象的观测(深层)-原型方法重写


下一篇,对象中新增对象的深层观测


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vue2.x 源码学习】第八篇 - 数组的深层劫持