Vue2源码分析-day2

news2024/11/23 19:13:18

实现数组的响应式原理

首先我们在index.html中定义一个数组,并且打印实例

const vm = new MVue({
    data() {
        return {
            name: "zhangsan",
            age: "16",
            hobby:['zhangsan','lisi']
        }
    }
})
console.log(vm);

我们会发现定义的数组每一项都有get和set方法虽然数组是被劫持了但是这样做性能非常差。如果说数组元素有1000个或者10000个能?那么我们要循环劫持1000次或者10000次吗?这显然是不合理的,所以我们对数组要单独做数据劫持。

在这里插入图片描述
数组一般用户都是push,pop这所方法去操作数组元素所以,我们要重写这些方法。

首先我们先判断是否为数组,obseve/index.js文件下Observer类修改如下代码

constructor(data) {
    /* 
        这里注意,Object.defineProperty只能劫持已经存在的属性,新增或删除的无法劫持
        这也是为什么vue2中新增了,$set和$delete方法这类方法的原因
    */

    if(Array.isArray(data)){
	
        // 重写原型对象上的方法
      	data.__proto__=new_array_proto
        // 劫持数组
        this.observe_array(data)
    }else{
        // 劫持对象
        this.walk(data)
    }

}
walk(data) {
    // 循环对象keys依次劫持,重新定义属性
    Object.keys(data).forEach(key => {
        define_reactive(data, key, data[key])
    })
}
observe_array(data){
    // 如果数组中包含对象,则走对象劫持
    data.forEach((item)=>observe(item))
}

observe/index.js文件下创建array.js文件用来重写数组方法。并且导出new_array_proto


// 获取原数组原型对象
const old_arr_proto=Array.prototype;

// 拷贝新原型对象
export let new_array_proto=Object.create(old_arr_proto);

// 定义所以变异方法
let methods=['push','pop','shift','unshift','reverse','sort','splice'];

methods.forEach((item)=>{   
    new_array_proto[item]=function(...args){

        console.log(123);
        // 调用原原型上的方法
        let res=old_arr_proto[item].call(this,...args);

        return res
    }
})

然后我们在index.html调用push方法看看控制台是否打印123。如果打印就说明重写成功

在这里插入图片描述

下面我们来对我们的变异方法做进一步处理。因为新增的属性并没有被劫持


// 获取原数组原型对象
const old_arr_proto=Array.prototype;

// 拷贝新原型对象
export let new_array_proto=Object.create(old_arr_proto);

// 定义所以变异方法
let methods=['push','pop','shift','unshift','reverse','sort','splice'];

methods.forEach((item)=>{   
    new_array_proto[item]=function(...args){

       
        // 调用原原型上的方法
        let res=old_arr_proto[item].call(this,...args);

        //对新增的属性进行观测
        let val;
        switch(item){
            case "push":
            case "unshift":
                val=args;
                break;
            case "splice":
                val=args.slice(2);
                break;
        }

        // this为当前变异方法的调用者。_ob_为观测类的实例
        if(val){
            this._ob_.observe_array(val)		// 可能到这里你会好奇这个_ob_是哪里来的。别急下面我将解释
        }

        return res
    }
})

observe/index.js文件下中构造函数增加如下代码。添加_ob_一方面是为了给已经观测的数据打上标识,另一方便是为了调用数组的变异方法时如果新增的是对象那么,通过_ob_获取到观测类实例对这个新增对象进行观测

    constructor(data) {
        /* 
            这里注意,Object.defineProperty只能劫持已经存在的属性,新增或删除的无法劫持
            这也是为什么vue2中新增了,$set和$delete方法这类方法的原因
        */

        // 对即将观测的数据添加_ob_属性。添加被观测标识
        Object.defineProperty(data, '_ob_', {
            value:this,
            enumerable:false    // 禁止枚举,防止死循环
        })

        if(Array.isArray(data))
        {
            // 重写原型对象上的方法
            data.__proto__=new_array_proto
            
            
            // 劫持数组
            this.observe_array(data)
        }else{
            // 劫持对象
            this.walk(data)
        }

    }

既然已经被观测的数据打上了表示,那么为了防止重复观测我们就可以在observe方法中添加如下代码

 // 对对象劫持
 if (typeof data !== 'object' || data === null) {
     return;
 }

 // 如果已经被检测过直接返回
 if(data._ob_ instanceof Observer){
     return data._ob_
 }

 // 如果一个对象被劫持过就不需要再次劫持,我们可以通过一个实例判断是否被劫持过
 return new Observer(data)

下面我们在index.html文件下push一个对象就可以看到这个对象也被观测到了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/850371.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

14.3.4 【Linux】使用 LVM thin Volume 让 LVM 动态自动调整磁盘使用率

想像一个情况,你有个目录未来会使用到大约 5T 的容量,但是目前你的磁盘仅有 3T,问题是,接下来的两个月你的系统都还不会超过 3T 的容量, 不过你想要让用户知道,就是他最多有 5T 可以使用就是了!…

并发多线程篇

线程的基础知识 面试题1:线程与进程的区别? 面试题2:并行和并发有什么区别? 面试题3:创建线程的方式有哪些? 面试题 4:runnable 和 callable 有什么区别? 面试题5:线程…

基于Centos7的Nginx源码安装

目录 1、准备安装环境 2、获取tar包: 3、解压创建软链接 4、创建用户和组 5、执行安装 6、创建服务脚本 7、开启nginx:​编辑​编辑 1、准备安装环境 yum insatall -y make gcc gcc-c pcre-devel #pcre-devel -- pcre库 #安装openssl-devel yum …

基于 CentOS 7 构建 LVS-DR 群集以及配置nginx负载均衡

目录 一、基于 CentOS 7 构建 LVS-DR 群集 1、前期准备 1、关闭防火墙 2、安装ifconfig 3、准备四台虚拟机 2、在DS上 2.1、配置LVS虚拟IP 2.2、手工执行配置添加LVS服务并增加两台RS 2.3、查看配置 3、在RS端(第三台、第四台) 上 3.1、配置W…

H7-TOOL的高速DAPLINK用于新版STM32CubeIDE V1.13及其以上版本的超简单实现方法(2023-08-08)

之前分享了一个方法,太繁琐了,H7-TOOL群的群友提供了一个方法,实现非常简单。1、使用STM32CubeMX或者自己创建一个STM32CubeIDE工程后,设置这两个地方即可: 配置调试器,设置完毕记得点击右下角的Apply 2、然…

【个人记录】CentOS7 编译安装最新版本Git

说明 使用yum install git安装的git版本是1.8,并不是最新版本,使用gitlab-runner托管时候会拉项目失败,这里使用编译源码方式安装最新版本的git。 基础环境安装 echo "nameserver 8.8.8.8" >> /etc/resolv.conf curl -o /…

Excel表格(一)

1.单一栏的宽度和高度设置 2.大标题的跨栏居中 3.让单元格内的文字------自动适应 4.序号递增 5.货币符号 6.日期格式的选择 选到单元格,选中对应的日期格式 7.自动求和的计算 然后在按住回车键即可求出当前行的金额 点击自动求和 8.冻结表格栏 9.排序 1.单栏排序 …

【性能类】—页面性能类

一、提升页面性能的方法有哪些? 1. 资源压缩合并,减少HTTP请求 图片、视频、js、css等资源压缩合并,开启HTTP压缩,把资源文件变小 2. 非核心代码异步加载 →异步加载的方式 → 异步加载的区别 异步加载的方式 ① 动态脚本加载…

【JavaWeb】 JavaScript 开发利器之 jQuery

🎄欢迎来到边境矢梦的csdn博文,本文主要讲解Java 中JavaScript 开发利器之 jQuery的相关知识🎄 🌈我是边境矢梦,一个正在为秋招和算法竞赛做准备的学生🌈 🎆喜欢的朋友可以关注一下&#x1faf0…

QT信号与槽的理解

文章目录 信号与槽的理解 信号与槽的理解 信号就是事件,比如button被点击的事件,ComboBox选项改变的事件,都是信号槽就是对信号进行响应的函数,可以是任意自定义函数一个信号可以对应多个槽多个信号可以对应一个槽信号的参数不能…

提升Element UI分页查询用户体验与交互:实现修改未保存提示

我实现的功能是在 element ui 的分页组件中进行分页查询时,如果当前有未保存的修改数据就提示用户,用户可以选择是否放弃未保存的数据。确认放弃就重新查询数据;选择不放弃,不重新查询,并且显示条数选择框保持原样&…

AWS中lambda与DynamoDB的集成

前言:我在整个集成过程中,存在最大的问题有两个, 1. 没有考虑到lambda函数的权限,即对DynamoDB或者其他如Kinesis的权限授权,导致无法写入或者读取。 2.最初使用了异步方式调用,导致无法写数据到DynamoDB…

STM32自带的DSP库的滤波初体验(一)

最近在弄STM32自带的DSP库里的滤波,记录一下: arm_fir_instance_q15 instance_q15_S; #define NUM_TAPS 16 //滤波系数的个数 #define BLOCK_SIZE 32 q15_t firStateF32[BLOCK_SIZE NUM_TAPS]; q15_t Fir_Coeff[NUM_TAPS] {-79, -136, 312, 6…

《合成孔径雷达成像算法与实现》Figure3.1

代码复现如下: clc close all clear all%参数设置 B 5.80e6; %信号带宽 T 7.26e-6; %脉冲持续时间 K B/T; %线性调频频率 alpha 5; %过采样率 F alpha*B; %采样频率 N F*T; %采样点数 dt T/N; …

85. 最大矩形

题目描述 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。 示例 1: 输入:matrix [["1","0","1","0","0"],["1…

Icon图标有哪些在线设计的工具推荐

虽然icon图标相对较小,但icon图标在设计中非常重要。高质量的icon图标通常可以决定设计工作的质量。高质量的在线生产icon工具可以提高设计师图标设计的效率。此外,优秀的图标设计师还可以让设计师快速开始图标设计工作。本文为您选择了五种在线生成icon…

python ffmpeg合并ts文件

当你从网站下载了一集动漫,然后发现是一堆ts文件,虽然可以打开,但是某个都是10秒左右,很不方便。 这时,可以用python合并ts文件。 (1)安装配置ffmpeg 官网下载ffmpeg-2023-08-07-git-d295b6b…

【工作中问题解决实践 十】一次内存泄露排查-MAT使用指南

最近体验了一把当医生的感觉,定位病根病因,感觉这种要揪出问题的感觉很爽,并不觉得麻烦,这里将整个排查过程记录一下,方便之后再遇到类似问题有应对之道。 问题背景 2023-07-18 早上还在睡梦中的俺被一条条报警消息铛…

CTF流量题解http1.pcapng

使用Wireshark工具打开流量文件http1.pcapng,如下图所示。 在过滤检索栏输入http,wireshark自动进行过滤。

【EI复现】基于阶梯碳交易的含P2G-CCS耦合和燃气掺氢的虚拟电厂优化调度(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…