面试题之vue的响应式

news2024/10/7 16:23:28

文章目录

  • 前言
  • 一、响应式是什么?
  • 二、Object.defineProperty
  • 二、简单模拟vue
  • 三、深度监听
  • 四、监听数组
  • 总结


前言

为了应对面试而进行的学习记录,可能不够有深度甚至有错误,还请各位谅解,并不吝赐教,共同进步。


一、响应式是什么?

我个人的简单理解就是数据在发生变化时候,能自动的执行某些我们需要的操作行为。在vue中就是我们首次将数据渲染到页面中后,如果我们后面在修改数据,页面中也会自动进行更新,很明显,vue帮我们完成了响应式。
我们先来讲述vue2的响应式实现。
后面在讲述vue3,因为他们实现的原理有区别。

二、Object.defineProperty

首先我们需要先了解Object.defineProperty(),这个方法可以帮助我们来劫持对象上面的属性,是实现响应式的核心内容。

我们先来基本使用用下Object.defineProperty()

		const data = {};
		let name = 'xiacan';
		/**
		 * 第一个参数: 要监听的对象
		 * 第二个参数: 要监听的属性
		 * 第三个参数:  一个有get函数和set函数的对象
		 */
		Object.defineProperty(data,"name",{
			get(){
				console.log("name属性被获取啦!");
				//返回值 就是我们data[name] 获取到的值
				return name;
			},
			set(value) {
				// value 就是 我们设置name属性时候赋值的值
				console.log("name属性被赋新值了:",value);
				name = value;
			}
		})
		console.log(data.name);
		data.name = 'xiazai';
		console.log(data.name);

执行后的结果:
在这里插入图片描述
是不是很简单,我们已经完成了对对象属性的监听,当对象被使用和修改时候,我们已经可以做我们需要的操作了。

二、简单模拟vue

上面我们了解了怎么监听对象,我们来简单的模拟一下vue。

//模拟视图更新
function updateView(){
	console.log("视图更新啦!");
}

// 具体进行数据监听的函数
function definePy(target, key, value){
	Object.defineProperty(target, key, {
		get() {
			//直接返回当前值
			return value;
		},
		set(newValue) {
			//判断是否是修改为新值,否则不更新视图
			if(newValue === value) return; 
			value = newValue;
			//更新视图
			updateView();
		}
	})
}

//监听数据函数
function observer(target){
	//判断如果是基本类型就不监听
	if(typeof target !== 'object' || target === null ) return target;
	
	//我们循环对象的所有属性
	for(let key in target){
		//监听每个属性 将对象 当前属性 当前属性值传入
		definePy(target,key,target[key])
	}
	
}

//初始数据
const data = {
	name: 'xiacan',
	age: 22
}
//开始监听数据
observer(data)

data.name = 'xiazai';
console.log(data.name);

运行截图:
在这里插入图片描述
我们这样就成功的简单模拟了vue的响应式。
但是我们还不够,不能对data进行深程度的监听。

三、深度监听

我们将初始数据层级加深:

//初始数据
const data = {
    name: 'xiacan',
    age: 22,
    like:{
        one:'xi'
    }
}
//开始监听数据
observer(data)
data.like.one = 'ai';

运行一下:
在这里插入图片描述
很明显,并未检测到like对象属性的变换。

我们进一步优化,能够进行深度监听数据

//模拟视图更新
function updateView(){
    console.log("视图更新啦!");
}

// 具体进行数据监听的函数
function definePy(target, key, value){
    // 进行深度循环
    observer(target[key]);
    
    Object.defineProperty(target, key, {
        get() {
            //直接返回当前值
            return value;
        },
        set(newValue) {
            //判断是否是修改为新值,否则不更新视图
            if(newValue === value) return;
            // 进行深度循环,再有新值时候
            observer(newValue);
            
            value = newValue;
            //更新视图
            updateView();
        }
    })
}

//监听数据函数
function observer(target){
    //判断如果是基本类型就不监听 同时返回
    if(typeof target !== 'object' || target === null ) return target;

    //我们循环对象的所有属性
    for(let key in target){
        //监听每个属性 将对象 当前属性 当前属性值传入
        definePy(target,key,target[key]);
    }

}

//初始数据
const data = {
    name: 'xiacan',
    age: 22,
    like:{
        one:'xi',
        two:'22'
    }
}
//开始监听数据
observer(data)

data.like.one = 'ai';
data.like.two = {
    a:1
};
data.like.two.a = 2;


运行一下:
在这里插入图片描述

我们需要在开始劫持data属性前,将当前属性在进行一次监听就可以实现深度监听了,因为前面我们已经写好了结束的条件就是如果是基本类型就不监听,同时返回,这样就不会死循环。
然后还需要在每次属性赋新值时候也进行一次进行深度循环,因为可能赋值一个对象,这样我们才能监听变化。

我们还需要进行下一步的优化,就是实现对数组的监听

四、监听数组

我们先来看一看对数组进行监听:

//初始数据
const data = {
    name: 'xiacan',
    age: 22,
    like:{
        one:'xi',
        two:'22'
    },
    num: [1, 2, 3]
}
//开始监听数据
observer(data)

data.num[0] = 11
data.num.push(4)

运行一下:
在这里插入图片描述
很显然,能监听到数组原来的数据变化,但是执行数组的方法时候未能监听。

我们要实现对数组的监听,我们需要修改一下数组的原型,在原型上定义方法,让我们来实现监听数组的变化。

//模拟视图更新
function updateView(){
    console.log("视图更新啦!");
}


//创建一个新对象,原型执行数组的原型,但是不会干扰原来的原型
const newArr = Object.create(Array.prototype);
//数组方法太多了,我们选几个常见的修改
[ 'push', 'unshift', 'shift', 'pop' ].forEach(newFunName =>{
    newArr[newFunName] = function () {
        //更新视图
        updateView();
        //执行数组原型上原始的方法
        Array.prototype[newFunName].call(this, ...arguments)
    }
})
// 具体进行数据监听的函数
function definePy(target, key, value){
    // 进行深度循环
    observer(target[key]);

    Object.defineProperty(target, key, {
        get() {
            //直接返回当前值
            return value;
        },
        set(newValue) {
            //判断是否是修改为新值,否则不更新视图
            if(newValue === value) return;

            // 进行深度循环,再有新值时候
            observer(newValue);

            value = newValue;
            //更新视图
            updateView();
        }
    })
}

//监听数据函数
function observer(target){
    //判断如果是基本类型就不监听 同时返回避免死递归
    if(typeof target !== 'object' || target === null ) return target;

    //判断如果是数组,我们就修改原型为我们新建的
    if (Array.isArray(target)){
        target.__proto__  = newArr;
    }

    //我们循环对象的所有属性
    for(let key in target){
        //监听每个属性 将对象 当前属性 当前属性值传入
        definePy(target,key,target[key]);
    }

}

//初始数据
const data = {
    name: 'xiacan',
    age: 22,
    like:{
        one:'xi',
        two:'22'
    },
    num: [1, 2, 3]
}
//开始监听数据
observer(data)

data.num.push(4);
data.num.pop();

运行一下:
在这里插入图片描述
我们干嘛要修改数组原型,因为我们不能污染全局的数组原型,所以我们就自己定义一个新的原型,然后在对数组的方法进行修改,在里面添加进入了更新视图的方法,这也是vue中监听数组的实现方法,然后我们在开始监听data数据时候,先进行判断,如果为数组,我们就将当前对象的原型改变为我们新建的原型。

总结

我们已经大致将vue实现响应式简单的模拟了一下了,其中我们可以发现对于对象新增属性和删除属性我们是无法监听到的,所以vue中有其他的专门方法来完成。对于数组,我们就需要重新修改原型来实现监听。在vue2中对于深度监听是一次不断循环来完成的,如果数据层级多,速度会变得慢。vue3使用proxy后速度会有提高,还支持检测属性的新增和删除,以及监听数组,后续学习后更新文章进行记录。

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

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

相关文章

如何做好 IT 项目管理?做好项目管理常用的9大项目管理平台、7大管理方法

一个好的管理,是70%在流程、规范、工具,剩下的30%自由发挥。一个不好的管理,只有地板,每个人都要自己想办法,够到天花板。一个好的工具,就是帮助团队够到天花板的台阶。——刘润 项目管理是一门复杂的艺术&…

统一的文件管理,团队轻松协作

目前IT行业大都采用项目经理制的管理方式,这种管理方式下各个部门间相互独立,同时各部门间也缺乏沟通协作。因此IT行业在文件管理上主要面临以下几个问题: 文档缺乏集中管理:企业在管理过程中产生的大量文件分散在各个部门中&…

Python升级 pip : python -m pip install --upgrade pip,socket.timeout加入超时处理方法

人生苦短,我用python 最近又遇到了一个小的报错问题, 趁现在我还没有忘记, 赶紧来写一写… python 安装包资料报错交流:点击此处跳转文末名片获取 WARNING: You are using pip version 19.3.1; however, version 20.0.2 is available. You…

系统学习Numpy(一)——numpy的安装与基础入门[向量、矩阵]

系列文章目录 numpy的安装与基础入门[向量、矩阵与维度] numpy的安装与基础入门[向量、矩阵与维度]系列文章目录前言numpy安装向量与矩阵生成向量生成矩阵向量类型前言 numpy是科学计算以及机器学习深度学习的基础必备工具,本文将介绍numpy的安装,以及…

C语言课设项目-51单片机-中断系统

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 51单片机的中断系统 一、中断的概念 二、51单片机的中断系统结构 三、中断允许控制 四、中断…

C#,初学琼林(06)——组合数的算法、数据溢出问题的解决方法及相关C#源代码

1 排列permutation 排列,一般地,从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列,叫做从n个元素中取出m个元素的一个排列(permutation)。特别地,当mn时,这个排列被称作全…

vs code c语言断点调试window版解决方案

序: 1、这一步不懂劝退多少人,博主搜到了多少博文都是mac的,结果发现都对不上! 先看最终效果演示 接下去我每个步骤,你都仔细看,漏看一个环境都对不上! 正文 1、先去看博主的c/c运行环境配置图…

10-vue3动画

文章目录1.vue的transition动画1.1transition的基本使用1.2transition组件的原理1.3过渡动画的class1.4class的命名规则和添加时机1.5显示的指定过渡时间1.6过渡的模式mode1.7动态组件的切换1.8.appear初次渲染2、animation动画2.1同时设置animation和transition3.结合第三方库…

【Bard】来自谷歌的“吟游诗人”

个人主页:【😊个人主页】 文章目录前言Bard与相关产品的对比Bard VS 弱智吧来自对手的评论ChatGPT文心一言总结:前言 相比较ChatGPT的话题不断,谷歌的“Bard”显然低调了许多,在“画大饼”失败一个多月后&#xff0c…

【Python开发手册】深入剖析Google Python开发规范:规范Python注释写作

💖 作者简介:大家好,我是Zeeland,全栈领域优质创作者。📝 CSDN主页:Zeeland🔥📣 我的博客:Zeeland📚 Github主页: Undertone0809 (Zeeland) (github.com)&…

高通开发系列 - linux kernel内核升级msm-4.9升级至msm-4.19(2)

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 MDSS PLL驱动问题msm-4.19内核适配nand flashMDSS PLL驱动问题 | /home/peeta/sc262R_private_rl/build-msm8909/tmp/work-shared/ms…

第01章_Java语言概述

第01章_Java语言概述 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 1. Java知识脉络图 1.1 Java基础全程脉络图 1.2 本章专题与脉络 2. 抽丝剥茧话Java 2.1 当前大学生就业形势 麦可思研究院…

C++之红黑树

文章目录前言一、概念二、性质三、结点的定义四、红黑树的结构五、插入操作1.插入代码2.左单旋3.右单旋4.插入新结点的情况分析与总结第一步、按照搜索二叉树的规则插入新结点第二步、分析插入结点后红黑树的性质是否被破坏动态演示:六、验证红黑树1.检测是否满足二…

口令暴力破解--Telnet协议暴力破解、数据库暴力破解与远程桌面暴力破解

Telnet协议暴力破解 Telnet Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。要开始一个telnet会话,必须输入用户名和密码来登录服务器。而一般服务器不会对用户名…

【数据结构】6.4 AVL树(C++)

【数据结构】——6.4 AVL树 没有学过二叉搜索树(也叫二叉排序树或二叉查找树)的小伙伴们建议先学习一下,这样阅读会更轻松哦 点我学习二叉搜索树 目录一、AVL树的概念1. 二叉搜索树的问题2. AVL树的性质二、AVL树实现平衡的方法1. 更新平衡因…

【音视频第11天】GCC论文阅读(2)

A Google Congestion Control Algorithm for Real-Time Communication draft-alvestrand-rmcat-congestion-03论文理解 看中文的GCC算法一脸懵。看一看英文版的,找一找感觉。 目录Abstract1. Introduction1.1 Mathematical notation conventions2. System model3.Fe…

Shader 海面/水面

首先用Terrain在场景中随便做个地形,当作海底 上面加个Plane作为海面 实现海水效果要考虑海水深度对颜色的影响,法线移动形成波浪,菲涅尔,高光等效果 深度 海水深的地方颜色深,浅的地方颜色浅,所以海边和…

fastDFS文件管理系统在linux下部署

1.概述 fastDFS分布式文件系统包括三个中要部分:追踪器、存储节点、客户端,可以使用文件存储,文件同步,文件访问等功能,用来存储大容量数据 存储节点集群: 横向扩容:增加存储容量 纵向扩容&…

liunx系统(VMware Workstation Pro)详细安装配置docker

​ 安装东西前要知道docker是什么,以及docker能都干什么,文章都是本人亲测然后写的过程. http://t.csdn.cn/iqbGg 博客文章链接详细介绍docker,以及部署MySQL,nginx等配置 一. liunx系统(VMware) 安装Docker 1. Docker中文网地址: Docker中文网 官网 (p2hp.com) 2. 打开VM…

50 Projects 50 Days - Progress Steps 学习记录

50 Projects 50 Days不使用任何前端框架,适合初学者练手,巩固前端基础,在这里记录一下学习过程,尤其是一些细节上的问题。 项目地址 Progress Steps 展示效果 Progress Steps 实现思路 进度条和结点分开处理: 1…