# 虚拟 DOM
> 面试题:什么是虚拟DOM?其优点有哪些?
**标准且浅显的答案**
>虚拟dom本质上就是一个普通的 JS 对象,用于描述视图的界面结构
虚拟 DOM 最早是由 React 团队提出来的,因此 React 团队在对虚拟 DOM 的定义上面有绝对的话语权。
>https://react.docschina.org/docs/faq-internals.html
**Virtual DOM 是一种编程概念。**在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中。
也就是说,只要我们有一种方式,能够将真实 DOM 的层次结构描述出来,那么这就是一个虚拟 DOM。
在 React 中,React 团队使用的是 JS 对象来对 DOM 结构进行一个描述。但是很多人会直接把 JS 对象和虚拟 DOM 划等号,这种理解是不太准确的,比较片面的。
虚拟 DOM 和 JS 对象之间的关系:**前者是一种思想,后者是一种思想的具体实现。**
## 为什么需要虚拟 DOM
使用虚拟 DOM 主要有两个方面的优势:
- 相较于 DOM 的体积优势和速度优势
- 多平台的渲染抽象能力
**相较于 DOM 的体积优势和速度优势**
首先我们需要明确一个点,JS 层面的计算速度要比 DOM 层面的计算要快:
- DOM 对象最终要被浏览器渲染出来之前,浏览器会有很多工作要做(浏览器的渲染原理)
- DOM 对象上面的属性也非常非常多
```js
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
```js
let newP = document.createElement("p");
let newContent = document.createTextNode("this is a test");
newP.appendChild(newContent);
document.body.appendChild(newP);
```
```js
document.body.innerHTML = `
this is a test
`; ``` 因此在使用 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 编译后结果如下:  在源码中 createElement 方法如下: ```js /** * * @param {*} type 元素类型 h1 * @param {*} config 属性对象 {id : "aa"} * @param {*} children 子元素 hello * @returns *