React虚拟DOM原理

释放双眼,带上耳机,听听看~!

1.什么是虚拟DOM

我们在前端面试的时候,经常会被问到什么是虚拟DOM。这个概念,感觉很熟悉,但又说不出它到底是什么。现在我们来探索一下到底什么是虚拟DOM。

首先我们看下什么是DOM,对于DOM,我们应该都很熟悉了,下面是MDN对于DOM的定义

文档对象模型 (DOM) 将 web 页面与到脚本或编程语言连接起来。通常是指 JavaScript,但将 HTML、SVG 或 XML 文档建模为对象并不是 JavaScript 语言的一部分。DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。DOM的方法(methods)让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行。

虚拟DOM自然就是跟DOM有很大关系的了。我们在使用原生JS开发或者使用Jquery开发,经常就会操作DOM,但是我们使用的时候发现,每次我们改变DOM的时候,页面再次渲染,会花费不短的一段时间,这样用户体验就不太好了。如果我们每次操作的不是DOM或者每次只操作更少的DOM呢,是不是会花费的时间更短呢,基于这个想法,就有了虚拟DOM。

在React中,会把DOM转换成JavaScript对象,然后再把JavaScript对象转化成DOM,这样我们对于DOM的操作,实际上是在操作这个JavaScript对象。

2.DOM是如何创建虚拟DOM的

我们利用在线babel工具来看下。左边是JSX,右边是JSX经过babel转换后的效果,事实上JSX是右边这种写法的语法糖,我们在React项目中写的JSX的写法都会转换成右边这种写法。
React虚拟DOM原理
在React项目中,使用以下这种写法,渲染出的效果也是一样的。


1
2
3
4
5
6
7
8
9
10
11
1import React from 'react';
2import ReactDOM from 'react-dom';
3
4let element = React.createElement("h1", {
5    id: "test",
6    className: "testClass"
7  }, "test");
8
9ReactDOM.render(element, document.getElementById('root'));
10
11

现在我们来分析以下上面的代码

  • React.createElement()方法传入了3个参数,第1个参数对应的是标签名称,第2个参数是属性,第三个参数是内容,然后返回某个值
  • ReactDOM.render()方法接收了两个参数,第一个参数是刚刚提到的某个值,第二个参数是获取到的root元素,对应的是index.html中的<div id="root"></div>

在上面的代码中加入console.log(element),打印出element的值,然后看到,原来某个值是这样的:
React虚拟DOM原理
由此说明:React.createElement()方法创建了虚拟DOM。

3.模拟实现React.createElement()

有上图可以这个对象有多个属性,目前来说对我们比较重要的是props和type属性,所以先实现对于这两个属性的操作。
React.createElement()接收3个参数,现在要把这3个参数合并到type和props中。
React.createElement()接收3个以上参数,说明该元素里面有多个子元素(这些子元素仍然是React.createElement()),那么把第二个参数后面的所有参数转换成数组放入children中


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1function ReactElement(type, props) {
2    const element = { type, props };
3    return element;
4}
5
6function createElement(type, config = {}, children) {
7    let propName;
8    const props = {};  // 定义props
9    for(propName in config) {
10        props[propName] = config[propName];  // 复制config的属性到props中
11    }
12
13    // 处理children
14    const childrenLength = arguments.length - 2;
15    if(childrenLength === 1) {
16        props.children = children;
17    } else {
18        // 有多个子元素的情况
19        props.children = Array.from(arguments).slice(2);
20    }
21
22    return ReactElement(type, props);
23}
24
25

加入以下代码测试下效果


1
2
3
4
5
6
7
8
1const element = createElement(&quot;h1&quot;, {
2    id: &quot;test&quot;,
3    className: &quot;testClass&quot;
4  }, createElement(&quot;span&quot;, null, &quot;span1&quot;), createElement(&quot;span&quot;, null, &quot;span2&quot;));
5
6console.log(JSON.stringify(element))
7
8

打印结果为:
React虚拟DOM原理
可以看到,最终,DOM转换成了JavaScript对象。

给TA打赏
共{{data.count}}人
人已打赏
安全技术

AES 加密解密 (javascript, java,php,c#)

2021-8-18 16:36:11

安全技术

C++ 高性能服务器网络框架设计细节

2022-1-11 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索