React 第三十二章 虚拟DOM

面试题:什么是虚拟DOM?其优点有哪些?
标准且浅显的答案
虚拟dom本质上就是一个普通的 JS 对象,用于描述视图的界面结构

虚拟 DOM 最早是由 React 团队提出来的,因此 React 团队在对虚拟 DOM 的定义上面有绝对的话语权。可以参考https://legacy.reactjs.org/docs/faq-internals.html

Virtual DOM 是一种编程概念 。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中。

也就是说,只要我们有一种方式,能够将真实 DOM 的层次结构描述出来,那么这就是一个虚拟 DOM。

image-20230223114000816

在 React 中,React 团队使用的是 JS 对象来对 DOM 结构进行一个描述。但是很多人会直接把 JS 对象和虚拟 DOM 划等号,这种理解是不太准确的,比较片面的。

虚拟 DOM 和 JS 对象之间的关系:前者是一种思想,后者是一种思想的具体实现。

为什么需要虚拟 DOM

使用虚拟 DOM 主要有两个方面的优势:

  • 相较于 DOM 的体积优势和速度优势
  • 多平台的渲染抽象能力

相较于 DOM 的体积优势和速度优势

首先我们需要明确一个点,JS 层面的计算速度要比 DOM 层面的计算要快:

  • DOM 对象最终要被浏览器渲染出来之前,浏览器会有很多工作要做(浏览器的渲染原理)
  • DOM 对象上面的属性也非常非常多
const div = document.createElement("div");
for(let i in div){console.log(i + " ")}

操作 JS 对象的时间和操作 DOM 对象的时间是完全不一样的。

JS 层面的计算速度要高于 DOM 层面的计算速度。

此时有一个问题:虽然使用了 JS 对象来描述 UI,但是最终不还是要用原生 DOM API 去操作 DOM 么?

虚拟 DOM 在第一次渲染页面的时候,并没有什么优势,速度肯定比直接操作原生 DOM API 要慢一些,虚拟 DOM 真正体现优势是在更新阶段。

根据 React 团队的研究,在渲染页面时,相比使用原生 DOM API,开发人员更加倾向于使用 innerHTML

let newP = document.createElement("p");
let newContent = document.createTextNode("this is a test");
newP.appendChild(newContent);
document.body.appendChild(newP);
document.body.innerHTML = `<p>this is a test</p>
`;

因此在使用 innerHTML 的时候,就涉及到了两个层面的计算:

  • JS 层面:解析字符串
  • DOM 层面:创建对应的 DOM 节点

接下来我们加入虚拟 DOM 来进行对比:

innerHTML虚拟 DOM
JS 层面计算解析字符串创建 JS 对象
DOM 层面计算创建对应的 DOM 节点创建对应的 DOM 节点

虚拟 DOM 真正发挥威力的时候,是在更新阶段

innerHTML 进行更新的时候,要全部重新赋值,这意味着之前创建的 DOM 节点需要全部销毁掉,然后重新进行创建

但是虚拟 DOM 只需要更新必要的 DOM 节点即可

innerHTML虚拟 DOM
JS 层面计算解析字符串创建 JS 对象
DOM 层面计算销毁原来所有的 DOM 节点修改必要的 DOM 节点
DOM 层面计算创建对应的 DOM 节点

多平台的渲染抽象能力

UI = f(state)这个公式进一步进行拆分可以拆分成两步:

  • 根据自变量的变化计算出 UI
  • 根据 UI 变化执行具体的宿主环境的 API

虚拟 DOM 只是多真实 UI 的一个描述,回头根据不同的宿主环境,可以执行不同的渲染代码:

  • 浏览器、Node.js 宿主环境使用 ReactDOM 包
  • Native 宿主环境使用 ReactNative 包
  • Canvas、SVG 或者 VML(IE8)宿主环境使用 ReactArt 包
  • ReactTest 包用于渲染出 JS 对象,可以很方便地测试“不隶属于任何宿主环境的通用功能”

React 中的虚拟DOM

在 React 中通过 JSX 来描述 UI,JSX 最终会被转为一个叫做 createElement 方法的调用,调用该方法后就会得到虚拟 DOM 对象。

经过 Babel 编译后结果如下:

image-20221226155735808

在源码中 createElement 方法如下:

/**** @param {*} type 元素类型 h1* @param {*} config 属性对象 {id : "aa"}* @param {*} children 子元素 hello* @returns* <h1 id="aa">hello</h1>*/
export function createElement(type, config, children) {let propName;const props = {};let key = null;let ref = null;let self = null;let source = null;// 说明有属性if (config != null) {// ...for (propName in config) {if (hasOwnProperty.call(config, propName) &&!RESERVED_PROPS.hasOwnProperty(propName)) {props[propName] = config[propName];}}}// 经历了上面的 if 之后,所有的属性都放到了 props 对象上面// props ==> {id : "aa"}// children 可以有多个参数,这些参数被转移到新分配的 props 对象上// 如果是多个子元素,对应的是一个数组const childrenLength = arguments.length - 2;if (childrenLength === 1) {props.children = children;} else if (childrenLength > 1) {const childArray = Array(childrenLength);for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}// ...props.children = childArray;}// 添加默认的 propsif (type && type.defaultProps) {const defaultProps = type.defaultProps;for (propName in defaultProps) {if (props[propName] === undefined) {props[propName] = defaultProps[propName];}}}// ...return ReactElement(type,key,ref,self,source,ReactCurrentOwner.current,props);
}const ReactElement = function (type, key, ref, self, source, owner, props) {// 该对象就是最终向外部返回的 vdom(也就是用来描述 DOM 层次结构的 JS 对象)const element = {// 让我们能够唯一地将其标识为 React 元素$$typeof: REACT_ELEMENT_TYPE,// 元素的内置属性type: type,key: key,ref: ref,props: props,// 记录负责创建此元素的组件。_owner: owner,};// ...return element;
};

在上面的代码中,最终返回的 element 对象就是我们所说的虚拟 DOM 对象。在官方文档中,官方更倾向于将这个对象称之为 React 元素。

真题解答

题目:什么是虚拟DOM?其优点有哪些?

参考答案:

虚拟 DOM 最初是由 React 团队所提出的概念,这是一种编程的思想,指的是针对真实 UI DOM 的一种描述能力。

在 React 中,使用了 JS 对象来描述真实的 DOM 结构。虚拟DOM和 JS 对象之间的关系:前者是一种思想,后者是这种思想的具体实现。

使用虚拟 DOM 有如下的优点:

  • 相较于 DOM 的体积和速度优势
  • 多平台渲染的抽象能力

相较于 DOM 的体积和速度优势

  • JS 层面的计算的速度,要比 DOM 层面的计算快得多
    • DOM 对象最终要被浏览器显示出来之前,浏览器会有很多工作要做(浏览器渲染原理)
    • DOM 上面的属性也是非常多的
  • 虚拟 DOM 发挥优势的时机主要体现在更新的时候,相比较 innerHTML 要将已有的 DOM 节点全部销毁,虚拟 DOM 能够做到针对 DOM 节点做最小程度的修改

多平台渲染的抽象能力

  • 浏览器、Node.js 宿主环境使用 ReactDOM 包
  • Native 宿主环境使用 ReactNative 包
  • Canvas、SVG 或者 VML(IE8)宿主环境使用 ReactArt 包
  • ReactTest 包用于渲染出 JS 对象,可以很方便地测试“不隶属于任何宿主环境的通用功能”

在 React 中,通过 JSX 来描述 UI,JSX 仅仅是一个语法糖,会被 Babel 编译为 createElement 方法的调用。该方法调用之后会返回一个 JS 对象,该对象就是虚拟 DOM 对象,官方更倾向于称之为一个 React 元素。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一物一码数字化营销进军调味品行业,五丰黎红“星厨俱乐部”火啦!

近日&#xff0c;由五丰黎红联合纳宝科技精心打造的小程序“星厨俱乐部”火啦&#xff01;一经上线就吸引了大量用户注册和参与&#xff0c;可以说取得了非常成功的市场反馈&#xff0c;那究竟是一个什么样的小程序&#xff0c;竟然有这么大的吸引力呢&#xff1f; 介绍小程序之…

不用投稿邮箱,怎样向各大新闻媒体投稿?

身为单位的信息宣传员,我深知肩上责任重大。每个月,完成单位在媒体上投稿发表文章的考核任务,就如同一场无声的赛跑,既要保证速度,更要注重质量。起初,我遵循“前辈们”的老路,一头扎进了邮箱投稿的海洋。但很快,现实给了我一记重拳——邮箱投稿的竞争犹如千军万马过独木桥,稿件…

JVM学习-虚拟机栈

虚拟机栈 每个线程创建时都会创建一个虚拟机栈&#xff0c;其内部保存一个个栈帧&#xff0c;对应一次次Java方法调用&#xff0c;栈是线程私有的。 生命周期: 与线程相同 作用 主管Java程序的运行&#xff0c;它保存方法的局部变量、部分结果、并参与方法的调用和返回。 …

JavaWeb文件上传/下载(Servlet)

效果 文件下载 文件上传 项目概述 Jakarta EE9&#xff0c;Web项目 项目文件结构 0 maven依赖&#xff0c;资源文件 <!-- lombok插件--> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId&g…

【JAVA】嵌入式软件工程师-2025校招必备-详细整理

一、Java 基础 1.JDK 和 JRE 有什么区别&#xff1f; jdk&#xff1a;java development kit jre&#xff1a;java runtime Environment jdk是面向开发人员的&#xff0c;是开发工具包&#xff0c;包括开发人员需要用到的一些类。 jre是java运行时环境&#xff0c;包括java虚拟机…

fl studio试用版文件保存无法打开??一个方法教你免费打开!

前言 当下&#xff0c;各款编曲软件五花八门&#xff0c;而这其中最有声誉的必为FL Studio莫属 这个软件呢国人习惯叫他水果&#xff0c;拥有强大的录音、编曲、混音等功能&#xff0c;所以广受音乐圈欢迎。如今&#xff0c;大部分水果一旦有编曲所需&#xff0c;一般都要使用…

# 从浅入深 学习 SpringCloud 微服务架构(十七)--Spring Cloud config(1)

从浅入深 学习 SpringCloud 微服务架构&#xff08;十七&#xff09;–Spring Cloud config&#xff08;1&#xff09; 一、配置中心的 概述 1、配置中心概述 对于传统的单体应用而言&#xff0c;常使用配置文件来管理所有配置&#xff0c;比如 SpringBoot 的 application.y…

MySQL 身份认证漏洞 CVE-2012-2122

漏洞影响版本 MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.演示 开启靶场 进入漏洞目录 cd /root/vulhub/mysql/CVE-2012-2122开启漏洞靶场 docker-compose up -d攻击 直接 运行 这个命令 for i i…

STM32F407 2个高级定时器生成2路无刷电机波形以及相电流采集程序(寄存器版)

stm32f407 高级定时1、定时8 生成20k 中心PWM 波形 并分别用其通道4 触发ADC1 ADC2 采样 用于分别两无刷电机foc 电流环控制&#xff0c;ADC1产生50us的电流采集完成中断&#xff0c;用于foc算法周期运算 主要参考高级定时器的寄存器和ADC寄存器 首先&#xff0c;要使用STM32F…

c++20---std::erase----std::erase_if

问题&#xff1a;如何删除满足条件的所有元素。 erase #include <iostream> #include <algorithm> #include <vector>int main(){std::vector<int> vec{1,2,3,1,1,1,1,1};std::erase(vec,1);for(int v:vec) std::cout<<v<<" "…

【计算机网络】物理层 通信基础、奈氏准则、香农公式 习题2

下列说法中正确的是( )。 A. 信道与通信电路类似&#xff0c;一条可通信的电路往往包含一个信道 B.调制是指把模拟数据转换为数字信号的过程 C. 信息传输速率是指通信信道上每秒传输的码元数 D.在数值上&#xff0c;波特率等于比特率与每符号所含的比特数的比值 信息传输速率&a…

CentOs安装

安装 开发工具 &#xff1a;GCC、 JDK、mysql 如果出现蓝屏&#xff0c;要在BIOS开启虚拟化支持&#xff0c;或者移除打印机。

西南大学计算机考研,选学硕还是专硕?西南大学计算机考研考情分析!

西南大学&#xff08;Southwest University&#xff09;是教育部直属&#xff0c;教育部、农业农村部、重庆市共建的重点综合大学&#xff0c;是国家首批"双一流"建设高校&#xff0c;"211工程"和"985工程优势学科创新平台"建设高校。现任党委书…

牛客NC343 和大于等于K的最短子数组【困难 前缀和 Java/Go】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/3e1fd3d19fb0479d94652d49c7e1ead1 思路 本答案利用前缀和解答&#xff0c;Java&#xff0c;Go答案通过&#xff0c;但是同样的代码用PHP的话有一个测试用例超时 应该还有更优秀的答案&#xff0c;后面找到更优…

fastadmin对登录token的处理

fastadmin对token的操作 最近开发遇到一个场景&#xff0c;需要绕过验证获取登录&#xff0c;所以恶补了一下这个知识点&#xff0c;这个主要就是控制fastadmin的token的问题 代码分步实现 class Xcxuser extends Api {//关于鉴权protected $noNeedLogin [login,getopenid,…

AWS简介

AWS AWS&#xff0c;全称为Amazon Web Services&#xff0c;是亚马逊公司旗下的云计算服务平台&#xff0c;自2006年起向全球用户提供广泛而深入的云计算服务。AWS是全球最全面、应用最广泛的云平台之一&#xff0c;它从全球的数据中心提供超过200项功能齐全的服务&#xff0c…

ospf基础

ospf 概述&#xff1a; 什么是ospf 开放式最短路径优先协议&#xff0c;一种最受欢迎的动态路由协议版本&#xff1a;ospfv2&#xff08;ipv4&#xff09;和ospfv3&#xff08;ipv6&#xff09;ospf位于OSI参考模型的第三层&#xff0c;数据封装在ip报头的后面协议号&#xf…

(2)双指针练习:复写零

复写零 题目链接&#xff1a;1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入…

详解绝对路径和相对路径的区别

绝对路径和相对路径是用于描述文件或目录在文件系统中位置的两种不同方式。 绝对路径&#xff08;Absolute Path&#xff09;是从文件系统的根目录开始的完整路径&#xff0c;可以唯一地确定一个文件或目录的位置。在不同的操作系统中&#xff0c;根目录的表示方式可能略有不同…

那些年我与c++的叫板(一)--string类自实现

引子&#xff1a;我们学习了c中的string类&#xff0c;那我们能不能像以前数据结构一样自己实现string类呢&#xff1f;以下是cplusplus下的string类&#xff0c;我们参考参考&#xff01; 废话不多说&#xff0c;直接代码实现&#xff1a;&#xff08;注意函数之间的复用&…