.JSX"为什么能“写 HTML”?因为有 Babel 在偷偷干活!

124 阅读5分钟

在 React 的世界里, JSX(JavaScript XML) 随处可见。它允许我们在 JavaScript 中写 HTML,甚至像写模板一样构建 UI,极大地提升了开发效率和代码可读性。

但你有没有想过:何为JSX ?为什么不能直接运行?它又是如何被转换编译的?Babel 又是干什么的?


一、何为JSX?

JSX(JavaScript XML) 是一种 JavaScript 的语法扩展,允许你以类似 HTML 的方式在 JavaScript 中编写结构化的 UI 元素。

示例:

const element = <h1>Hello World</h1>;

这段代码看起来像 HTML,但它其实是 JSX 语法。浏览器无法直接运行它,需要通过工具(如 Babel)将其转换为标准的 JavaScript 代码。


二、为什么不能直接运行 JSX?

因为 JSX 并不是原生 JavaScript 的语法。它属于 React 的开发工具链的一部分。浏览器不认识 <h1> 这样的标签,只能识别 JavaScript 的对象、函数等基本结构。

转换后的真实代码:

var element = /*#__PURE__*/React.createElement("h1", null, "Hello World");

这行代码才是浏览器可以执行的代码。它调用了 React.createElement 函数,创建了一个 React 元素对象。


三、JSX 是如何转换为 React.createElement 的?

来看下下面这段代码

function App() {
  const [todos, setTodos] = useState([
    { id: 1, title: 'todo1' },
    { id: 2, title: 'todo2' },
    { id: 3, title: 'todo3' }
  ]);

  const element = <h1 className='title'>Hello World</h1>;
  const element2 = createElement('h1', { className: 'title', id: 'tit' }, 'Hello World');

  return (
    <>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>

      <ul>
        {todos.map(todo => (
          createElement('li', { key: todo.id }, todo.title)
        ))}
      </ul>

      {element}
      {element2}
    </>
  );
}

这段代码中使用了两种方式创建 React 元素:

  1. 使用 JSX 语法创建元素
  2. 使用 React.createElement 手动创建元素

1. JSX 方式:

const element = <h1 className='title'>Hello World</h1>;

这是标准的 JSX 写法。它在开发时非常直观,但在运行前必须被 Babel 转换为 React.createElement 调用。

2. createElement 方式:

const element2 = createElement('h1', { className: 'title', id: 'tit' }, 'Hello World');

这是 JSX 被转换后的等价写法。React.createElement 接收三个参数:

  • type:元素类型(字符串 'h1',或组件 MyComponent
  • props:属性对象(如 className, id
  • children:子元素(可以是字符串、数字、其他元素)

四、JSX 与 React.createElement 的关系

JSX 是 React.createElement 的语法糖。

也就是说,JSX 最终都会被 Babel 转换为 React.createElement 的调用

示例:

<li key={todo.id}>{todo.title}</li>

会被 Babel 转换为:

React.createElement('li', { key: todo.id }, todo.title);

这也是为什么你可以在一个 React 项目中同时使用 JSX 和 React.createElement,它们本质上是等价的。


五、JSX 的特性与注意事项

✅ JSX 的优点:

  • 结构清晰:UI 层代码更直观。
  • 嵌套自然:像写 HTML 一样嵌套组件。
  • 开发效率高:配合 React DevTools 可视化调试方便。

⚠️ JSX 的注意事项:

1. 必须引入 React(逗你呢!Reat 17以上的版本就没这说法了)

在React 17 之前,即使你没有显式使用 React,会报错React is not defined,所以你必须在文件顶部写:

import React from 'react';
🚀 React 17 的新特性:运行时自动引入 React

React 17 开始,Facebook 团队与 Babel 团队合作,推出了一项新特性:

新的 JSX 转换方式(New JSX Transform)

它不再需要你手动 import React from 'react',因为:

  • JSX 不再转换为 React.createElement(...)
  • 而是转换为一个自动引入的、内部的 jsx 函数。

2. 不能返回多个根元素

一个组件的 return 中只能有一个根元素,可以使用 <>...</><div>...</div> 包裹:

return (
  <>
    <h1>Hello</h1>
    <p>World</p>
  </>
);

3. 不能使用 class 属性

在 JSX 中,class 是 JavaScript 的保留字,所以要写成 className

<h1 className="title">Hello</h1>

4. 不能使用 for 属性

<label for="input"> 是 HTML 的写法,但在 JSX 中要写成 htmlFor

<label htmlFor="input">用户名</label>

🤓 为什么?
因为 for也是 JavaScript 的保留关键字,用于 for 循环。所以 React 选择了 htmlFor 来代替 HTML 中的 for 属性。


六、JSX 是如何被编译的?Babel 的作用

1. 安装 Babel 工具链

bun add --dev @babel/cli @babel/core @babel/preset-env @babel/preset-react
  • @babel/cli:命令行工具,用于手动编译文件。
  • @babel/core:Babel 的核心引擎。
  • @babel/preset-env:将 ES6+ 转换为 ES5。
  • @babel/preset-react:支持 JSX 语法。

2. 创建 .babelrc 配置文件

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

3. 使用 Babel 编译 JSX 文件

./node_modules/.bin/babel 1.jsx -o 2.js

这个命令会将 1.jsx 中的 JSX 和 ES6+ 语法转换为浏览器可以运行的 ES5 代码。


七、为什么需要 Babel?

Make JavaScript Great Again!

让js再次伟大!!! 哈哈哈哈

Babel 的核心功能:

  • ES6+ 语法 转换为 ES5,兼容旧浏览器。
  • JSX 转换为 React.createElement 调用。
  • 支持 TypeScript、Flow、JSX 等多种扩展语法。
  • 提供插件机制,高度可扩展。

举个例子:

你写:

const greet = (name) => `Hello, ${name}`;

Babel 会帮你转成:

var greet = function greet(name) {
  return 'Hello, ' + name;
};

这样即使你的浏览器不支持箭头函数,也能正常运行。


八、开发依赖 vs 生产依赖:devDependenciesdependencies 有什么区别?

package.json 中,我们通常会看到两个依赖项分类:

{
  "dependencies": {
    "react": "^19.1.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.28.0",
    "@babel/core": "^7.28.0"
  }
}

解释

类型英文中文作用举例
生产依赖dependencies上线时也需要的依赖应用正常运行所必须react, react-dom, lodash
开发依赖devDependencies开发时才需要的依赖构建、编译、测试等工具babel, eslint, webpack

理解

  • dependencies 就像你家里的家具:没有它们,家就住不了。
  • devDependencies 就像你装修时用的工具:装修完就收起来了,不需要带进房间。

为什么上线不用 Babel?

因为 Babel 只在开发阶段使用。上线时,代码已经被编译成标准的 JavaScript,不再需要 Babel。


JSX 让 React 的开发体验更直观、更高效,而 Babel 是让这一切成为可能的“幕后英雄”。理解 JSX 和 Babel 的关系,是掌握 React 开发的关键一步。