当前位置: 首页 > news >正文

面试题之vue的响应式

文章目录

  • 前言
  • 一、响应式是什么?
  • 二、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后速度会有提高,还支持检测属性的新增和删除,以及监听数组,后续学习后更新文章进行记录。

相关文章:

面试题之vue的响应式

文章目录前言一、响应式是什么?二、Object.defineProperty二、简单模拟vue三、深度监听四、监听数组总结前言 为了应对面试而进行的学习记录,可能不够有深度甚至有错误,还请各位谅解,并不吝赐教,共同进步。 一、响应式…...

聚焦弹性问题,杭州铭师堂的 Serverless 之路

作者:王彬、朱磊、史明伟 得益于互联网的发展,知识的传播有了新的载体,使用在线学习平台的学生规模逐年增长,越来越多学生在线上获取和使用学习资源,其中教育科技企业是比较独特的存在,他们担当的不仅仅是…...

NDK RTMP直播客户端二

在之前完成的实战项目【FFmpeg音视频播放器】属于拉流范畴,接下来将完成推流工作,通过RTMP实现推流,即直播客户端。简单的说,就是将手机采集的音频数据和视频数据,推到服务器端。 接下来的RTMP直播客户端系列&#xff…...

Python3--垃圾回收机制

一、概述 Python 内部采用 引用计数法,为每个对象维护引用次数,并据此回收不在需要的垃圾对象。由于引用计数法存在重大缺陷,循环引用时由内存泄露风险,因此Python还采用 标记清除法 来回收在循环引用的垃圾对象。此外&#xff0c…...

C/C++开发,认识opencv各模块

目录 一、opencv模块总述 二、opencv主要模块 2.1 opencv安装路径及内容 2.2 opencv模块头文件说明 2.3 成熟OpenCV主要模块 2.4 社区支持的opencv_contrib扩展主要模块 2.5 关于库文件的引用 一、opencv模块总述 opencv的主要能力在于图像处理,尤其是针对二维图…...

【WLSM、FDM状态估计】电力系统状态估计研究(Matlab代码实现)

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

准备2023(2024)蓝桥杯

前缀和 一维前缀和 s[i]s[i-1]a[i]二维前缀和&#xff08;子矩阵的和&#xff09; s[i][j]s[i-1][j]s[i][j-1]-s[i-1][j-1]a[i][j] 差分 一维数组 //b是差分数组b[i]c;b[j1]-c;例题 #include<iostream> using namespace std; int n,m; int b[100002],a[100002]; vo…...

剑指 Offer 60. n个骰子的点数

剑指 Offer 60. n个骰子的点数 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 把n个骰子扔在地上&#xff0c;所有骰子朝上一面的点数之和为s。输入n&#xff0c;打印出s的所有可能的值出现的概率。 你需要用一个浮点数数组返回答案&#xff0c;其中第 i 个…...

阿里巴巴-淘宝搜索排序算法学习

模型效能&#xff1a;模型结构优化 模型效能&#xff1a;减枝 FLOPS&#xff1a;每秒浮点运算的次数 模型效能&#xff1a;量化 基于统计阈值限定&#xff0c;基于学习阈值限定。 平台效能&#xff1a;一站式DL训练平台 平台效能&#xff1a;搜索模型的系统流程 协同关系…...

〖Python网络爬虫实战⑮〗- pyquery的使用

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付费…...

SQL综合查询下

SQL综合查询下 目录SQL综合查询下18、查询所有人都选修了的课程号与课程名题目代码题解19、SQL查询&#xff1a;查询没有参加选课的学生。题目代码20、SQL查询&#xff1a;统计各门课程选修人数&#xff0c;要求输出课程代号&#xff0c;课程名&#xff0c;有成绩人数&#xff…...

全连接层FC

lenet结构: 输入层(Input Layer):接收手写数字的图像数据,通常是28x28的灰度图像。 卷积层1(Convolutional Layer 1):对输入图像进行卷积操作,提取低级别的特征,使用 6 个大小为 5x5 的卷积核进行卷积,得到 6 个输出特征图,激活函数为 Sigmoid。 平均池化层1(Aver…...

图的遍历及连通性

文章目录 图的遍历及连通性程序设计程序分析图的遍历及连通性 【问题描述】 根据输入的图的邻接矩阵A,判断此图的连通分量的个数。 【输入形式】 第一行为图的结点个数n,之后的n行为邻接矩阵的内容,每行n个数表示。其中A[i][j]=1表示两个结点邻接,而A[i][j]=0表示两个结点无…...

DJ3-4 实时调度

目录 3.4.1 实现实时调度的基本条件 1. 提供必要的信息 2. 系统的处理能力强 3. 采用抢占式调度机制 4. 具有快速切换机制 3.4.2 实时调度算法的分类 1. 非抢占式调度算法 2. 抢占式调度算法 3.4.3 常用的几种实时调度算法 1. 最早截止时间优先 EDF&#xff08;Ea…...

Oracle之PL/SQL游标练习题(三)

游标练习题目1、定义游标&#xff1a;列出每个员工的姓名部门名称并编程显示第10个到第20个记录2、定义游标&#xff1a;从雇员表中显示工资大于3000的记录&#xff0c;只要姓名、部门编号和工资&#xff0c;编程显示其中的奇数记录3、用游标显示所有部门编号与名称&#xff0c…...

docker运行服务端性能监控系统Prometheus和数据分析系统Grafana

文章目录一、Prometheus的安装和运行1、使用docker拉取镜像2、创建prometheus.yml文件3、启动容器4、查看启动是否成功5、记录安装过程中出现的错误二、Grafana的安装和运行1、使用docker拉取镜像2、创建grafana3、运行grafana4、查看grafana运行日志5、登录grafana一、Prometh…...

【Linux】【应用层】多线程编程

一、线程创建 Linux 中的 pthread_create() 函数用来创建线程&#xff0c;它声明在<pthread.h>头文件中&#xff0c;语法格式如下&#xff1a; int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine) (void *),void *arg);各个参数…...

GameFramework 框架详解之 如何接入热更框架HybridCLR

一.前言 HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的c#热更新方案 GameFramework是一个非常出色完整的基于Unity引擎的游戏框架,里面包含了非常多的模块,封装非常完整。 以前市面上的热更大多数都是Lua为主,后来出了一个ILRuntime的C#热更框架,虽然性能…...

全国青少年软件编程(Scratch)等级考试二级考试真题2023年3月——持续更新.....

一、单选题(共25题,共50分) 1. 小猫的程序如图所示,积木块的颜色与球的颜色一致。点击绿旗执行程序后,下列说法正确的是?( ) A.小猫一直在左右移动,嘴里一直说着“抓到了”。 B.小猫会碰到球,然后停止。 C.小猫一直在左右移动,嘴里一直说着“别跑” D.小猫会碰到球,…...

HTML2.1列表标签

列表标签种类 无序列表 有序列表 自定义列表 使用场景&#xff1a;在列表中按照行展示关联性内容。 特点&#xff1a;按照行的形式&#xff0c;整齐显示内容。 一、无序列表 标签名说明ul无序列表整体&#xff0c;用于包裹li标签li表示无序列表的每一项&#xff0c;用于包…...

三步构建高效笔记迁移系统:Obsidian Importer完全指南

三步构建高效笔记迁移系统&#xff1a;Obsidian Importer完全指南 【免费下载链接】obsidian-importer Obsidian Importer lets you import notes from other apps and file formats into your Obsidian vault. 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-import…...

使用taotaokencli工具一键配置多开发环境下的ai代理

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用 TaoToken CLI 工具一键配置多开发环境下的 AI 代理 基础教程类&#xff0c;介绍如何通过 npx 或全局安装 TaoToken 提供的命令…...

从PI到PR:静止坐标系下永磁同步电机电流控制的新范式

1. 永磁同步电机控制的痛点与变革 每次调试永磁同步电机&#xff08;PMSM&#xff09;时&#xff0c;最让人头疼的就是参数漂移问题。记得去年做伺服系统项目&#xff0c;电机运行半小时后电流波形就开始畸变——电感值因温升变化了15%&#xff0c;导致PI控制器输出的d轴电流出…...

UX-MCP服务器:基于Model Context Protocol的AI设计助手实现

1. 项目概述&#xff1a;UX-MCP服务器是什么&#xff1f;最近在AI应用开发圈里&#xff0c;一个词被频繁提及&#xff1a;MCP&#xff0c;也就是Model Context Protocol。简单来说&#xff0c;它是一套标准协议&#xff0c;旨在让AI助手&#xff08;比如Claude、Cursor等&#…...

如何3步快速掌握DataCleaner:开源数据质量工具完全指南

如何3步快速掌握DataCleaner&#xff1a;开源数据质量工具完全指南 【免费下载链接】DataCleaner The premier open source Data Quality solution 项目地址: https://gitcode.com/gh_mirrors/dat/DataCleaner 你是否曾为数据中的错误和缺失而烦恼&#xff1f;DataClean…...

基于Arduino与蓝牙的智能夜灯DIY:从硬件到App全流程解析

1. 项目概述&#xff1a;打造你的专属蓝牙智能夜灯如果你对Arduino和物联网项目感兴趣&#xff0c;一直想亲手做一个既能远程控制、又能播放音乐的智能小玩意儿&#xff0c;那么这个“8BitBox”项目绝对值得一试。它本质上是一个由Arduino驱动、通过Android手机蓝牙控制的智能夜…...

数电期末救星:5分钟搞懂钟控触发器(RS/D/JK/T)的区别与波形图画法

数电期末速成指南&#xff1a;钟控触发器核心要点与波形图实战技巧 期末考试前的最后一晚&#xff0c;数字电路教材上那些密密麻麻的触发器符号和波形图是否让你感到头晕目眩&#xff1f;别担心&#xff0c;本文将用最直接的方式帮你理清钟控触发器的核心逻辑&#xff0c;特别…...

WindowResizer:终极免费的Windows窗口强制调整工具

WindowResizer&#xff1a;终极免费的Windows窗口强制调整工具 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 你是否遇到过那些固执的应用程序窗口&#xff0c;无论你怎么拖动都无…...

Laravel-admin图表组件终极指南:从零实现ECharts与Chart.js数据可视化

Laravel-admin图表组件终极指南&#xff1a;从零实现ECharts与Chart.js数据可视化 【免费下载链接】laravel-admin Build a full-featured administrative interface in ten minutes 项目地址: https://gitcode.com/gh_mirrors/la/laravel-admin Laravel-admin作为一款高…...

Adobe-GenP 3.0:解锁Adobe全家桶功能的5分钟终极指南 [特殊字符]

Adobe-GenP 3.0&#xff1a;解锁Adobe全家桶功能的5分钟终极指南 &#x1f680; 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP Adobe-GenP 3.0是一款强大的Adobe C…...