深入理解 JSX:本质、原理与实践

917 阅读3分钟

1. 什么是 JSX?

JSX(JavaScript XML)是一种 JavaScript 的语法扩展,允许我们在 JavaScript 代码中编写类似 HTML 的结构。它最初由 React 团队提出,用于更直观地描述 UI 组件。

1.1 JSX 示例

const element = <h1 className="title">Hello, JSX!</h1>;

这看起来像 HTML,但实际上它是 JavaScript!

1.2 JSX 不是 HTML

虽然 JSX 看起来像 HTML,但它有几点不同:

  • 属性使用驼峰命名(如 className 而不是 class)。

  • 可以嵌入 JavaScript 表达式(用 { } 包裹)。

  • 最终会被编译成 JavaScript 代码,而不是直接渲染为 HTML。

2. JSX 的本质:编译后的 JavaScript

JSX 不能直接在浏览器中运行,它需要被编译成标准的 JavaScript。最常见的编译工具是 Babel

2.1 JSX 编译过程

假设我们有一个简单的 JSX:

const element = <div id="app">Hello, {name}!</div>;

经过 Babel 编译后,它会变成:

const element = React.createElement(
  "div",
  { id: "app" },
  "Hello, ",
  name,
  "!"
);

2.2 React.createElement() 的作用

React.createElement() 会返回一个 React Element(一个普通的 JavaScript 对象),描述 UI 的结构:

{
  type: "div",
  props: {
    id: "app",
    children: ["Hello, ", name, "!"]
  },
  // ...其他内部属性(如 key、ref)
}

这个对象就是 虚拟 DOM(Virtual DOM) 的一部分,React 用它来高效地更新真实 DOM。

3. 为什么需要 JSX?

3.1 更直观的 UI 描述

对比纯 JavaScript 写法:

// 纯 JavaScript(React 不使用 JSX)
const element = React.createElement(
  "div",
  { className: "container" },
  React.createElement("h1", null, "Hello"),
  React.createElement("p", null, "Welcome to JSX!")
);

使用 JSX 后:

// 使用 JSX
const element = (
  <div className="container">
    <h1>Hello</h1>
    <p>Welcome to JSX!</p>
  </div>
);

显然,JSX 更接近 HTML,可读性更强,尤其适合复杂 UI 结构。

3.2 支持 JavaScript 表达式

JSX 可以嵌入 JavaScript 表达式:

const name = "Alice";
const element = <p>Hello, {name.toUpperCase()}!</p>;

编译后:

const element = React.createElement(
  "p",
  null,
  "Hello, ",
  name.toUpperCase(),
  "!"
);

3.3 静态类型检查 & 优化

  • TypeScriptESLint 可以对 JSX 进行静态分析,提前发现错误。

  • BabelWebpack 可以优化 JSX 编译后的代码,提升性能。

4. JSX 底层原理

4.1 JSX 的运行时依赖

默认情况下,JSX 会被编译成 React.createElement(),所以 React 必须处于作用域内

import React from "react"; // 必须引入,即使没有直接使用 React
const element = <div>Hello</div>; // 编译后:React.createElement("div", null, "Hello")

4.2 自定义 JSX 编译函数(非 React 环境)

JSX 并不绑定 React,你可以配置 Babel 使用其他函数(如 Vue 的 h()):

// 在 Vue 3 中,JSX 会被编译成 `h()` 函数
const element = <div>Hello</div>;
// 编译后:h("div", null, "Hello")

Babel 配置(@babel/preset-react):

{
  "presets": [
    ["@babel/preset-react", {
      "pragma": "h" // 使用 h() 代替 React.createElement()
    }]
  ]
}

5. 常见问题 & 进阶用法

5.1 JSX 必须返回单个根元素

由于 JSX 最终会转换成 React.createElement(),而该函数只能返回一个元素,因此:
❌ 错误:

return (
  <h1>Title</h1>
  <p>Content</p>
);

✅ 正确:

return (
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
);

或者使用 Fragment(避免额外 DOM 节点):

return (
  <>
    <h1>Title</h1>
    <p>Content</p>
  </>
);

5.2 JSX 防止注入攻击(XSS)

React 会自动转义 JSX 中的变量,防止 XSS:

const userInput = "<script>alert('XSS')</script>";
const element = <div>{userInput}</div>; // 安全,会被转义成文本

5.3 JSX 与 key 属性

在循环中渲染列表时,必须提供 key 以优化 React 的 diff 算法:

const items = ["Apple", "Banana", "Orange"];
return (
  <ul>
    {items.map((item, index) => (
      <li key={index}>{item}</li>
    ))}
  </ul>
);

6. 总结

关键点

说明

JSX 是什么

JavaScript 的语法扩展,类似 HTML 但本质是 JavaScript

JSX 编译后

变成 React.createElement() 调用,返回 React Element(虚拟 DOM)

为什么用 JSX

更直观、支持 JavaScript 表达式、优化开发体验

JSX 不限于 React

可配置 Babel 用于 Vue、Preact 等其他库

最佳实践

单根元素、使用 key、防止 XSS

JSX 让前端开发更声明式,是 React 生态的核心特性之一。理解它的编译原理,有助于更好地掌握 React 和现代前端框架的工作机制。