创见博客
虚拟DOM(Virtual DOM)
七崽爱吃小饼干2026/01/04阅读 0专栏 React

React 虚拟 DOM(Virtual DOM)详解

一、虚拟 DOM 的核心定义

虚拟 DOM(Virtual DOM,简称 VDOM)是对真实 DOM 的一种轻量级、结构化的 JavaScript 对象描述。它并非真实的 DOM 节点,而是通过普通 JS 对象模拟了真实 DOM 的层级结构、标签名、属性(props)、子节点(children)等核心信息,是真实 DOM 在内存中的“镜像副本”。

举个简单的 React 虚拟 DOM 示例(对应真实的 <div class="container">Hello Virtual DOM</div>):

javascript
// 虚拟 DOM 本质:JS 对象
const virtualDom = {
  type: 'div',        // 对应真实 DOM 的标签名
  props: {            // 对应真实 DOM 的属性/特性
    className: 'container'
  },
  children: ['Hello Virtual DOM']  // 子节点(文本或其他虚拟 DOM 对象)
};

二、虚拟 DOM 的核心目的:解决真实 DOM 操作的性能瓶颈

虚拟 DOM 存在的核心价值是提升大量、复杂 DOM 操作时的应用性能,这源于真实 DOM 的两个关键问题:

  1. 真实 DOM 节点包含大量冗余属性(如 offsetLeft、style、dataset 等),操作真实 DOM 会触发浏览器的重排(Reflow)或重绘(Repaint),这两个过程开销极大,频繁操作会导致页面卡顿;
  2. 前端应用复杂度提升后,手动维护 DOM 状态与数据状态的同步会变得异常繁琐,容易出现 Bug。

虚拟 DOM 通过“间接操作”的方式,规避了直接操作真实 DOM 的性能损耗,同时简化了 DOM 状态管理。

三、虚拟 DOM 的核心工作流程(三步核心机制)

虚拟 DOM 的工作流程围绕“数据驱动视图”展开,核心分为三步:

1. 生成虚拟 DOM:从 React 元素到 VDOM 树

当 React 组件初始化或数据(state/props)发生变化时,React 会根据组件的渲染逻辑(render 方法或函数组件返回值),生成对应的虚拟 DOM 树(本质是一组嵌套的 JS 对象)。 例如函数组件的渲染过程:

jsx
function App() {
  const [count, setCount] = React.useState(0);
  // 组件返回的 JSX 会被 Babel 编译为 React.createElement,最终生成虚拟 DOM
  return (
    <div className="app">
      <p>计数:{count}</p>
      <button onClick={() => setCount(count + 1)}>点击+1</button>
    </div>
  );
}

上述 JSX 会被编译为 React.createElement 调用,最终生成对应的虚拟 DOM 树,描述当前页面的期望状态。

2. 对比虚拟 DOM:Diff 算法计算差异(核心优化步骤)

当数据发生变化(如点击按钮修改 count),React 会生成一份新的虚拟 DOM 树,然后通过内置的Diff 算法,对比新旧两份虚拟 DOM 树的结构和属性,精准找出两者之间的最小差异(补丁 patch)。

React 的 Diff 算法做了针对性优化(提升对比效率):

  • 按“层级对比”:只对比同一层级的虚拟 DOM 节点,不跨层级对比(减少无效遍历);(可以降低比较的时间复杂度)
  • 按“key 标识”:对于列表节点,通过 key 属性标识唯一节点,避免错误复用节点;
  • 按“类型预判”:如果两个节点的标签类型不同(如 div 变为 p),直接销毁旧节点并创建新节点,不深入对比内部属性。

通过这些优化,Diff 算法能以接近 O(n) 的时间复杂度完成对比(n 为虚拟 DOM 节点数量),大幅提升效率。

3. 应用差异:批量更新真实 DOM

React 不会直接将新的虚拟 DOM 树完整渲染为真实 DOM,而是只将 Diff 算法计算出的最小差异,批量更新到真实 DOM 中。

这种“批量更新+最小操作”的模式,最大程度减少了真实 DOM 的操作次数,规避了频繁重排/重绘带来的性能损耗,同时让开发者无需手动操作 DOM,只需关注数据状态的变化。

四、虚拟 DOM 与 JSX 的关系

JSX 是虚拟 DOM 的语法糖,两者并非同一概念,核心关系如下:

  1. JSX 是开发者编写 React 组件的便捷语法,它看起来像 HTML,却能嵌入 JS 逻辑(如 {count} 插值),降低了编写虚拟 DOM 的成本;
  2. 浏览器无法直接识别 JSX,必须通过 Babel 等编译工具,将 JSX 编译为 React.createElement 函数调用;
  3. React.createElement 函数的返回值,就是虚拟 DOM 对象(JS 对象),即:JSX → 编译 → React.createElement → 虚拟 DOM。

例如,以下 JSX 代码:

jsx
<p className="text" style={{ color: 'red' }}>Hello JSX</p>

会被编译为:

javascript
React.createElement(
  'p',  // 标签类型
  { className: 'text', style: { color: 'red' } },  // props 属性
  'Hello JSX'  // 子节点
);

而上述 React.createElement 调用的返回值,就是对应的虚拟 DOM 对象。

总结

  1. 是什么:虚拟 DOM 是真实 DOM 的 JS 对象描述,核心作用是提升复杂 DOM 操作的性能;

  2. 解决了什么问题:频繁操作真实DOM会导致频繁的重排和重绘,开销会很大,性能会很差。

  3. 核心工作流程:生成旧虚拟 DOM → 数据变化生成新虚拟 DOM → Diff 算法找差异(新旧虚拟DOM树) → 批量更新真实 DOM;

  4. Diff 算法是性能优化核心,通过层级对比、key 标识等策略实现高效差异检测;

  5. 通过批量更新真实DOM,减少操作真实DOM的次数,从而减少重拍、重绘的次数,提高效率。

  6. JSX 是虚拟 DOM 的语法糖,最终会编译为生成虚拟 DOM 的函数调用。

  7. 虚拟DOM使得跨平台成为了可能

    • 虚拟DOM是js对象,不直接依赖浏览器环境
    • 例如React Native、以及服务端渲染SSR
评论
0/100