当前位置: 首页 > 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;用于包…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...