React 是如何用 JSX 写页面,却能被浏览器执行的?——Babel 的魔法解析

一、引言:React 为什么可以直接写 HTML 样式的代码?

如果你刚刚开始学习 React,你可能会有这样的疑问:

"我明明在 .js 文件里写了类似 HTML 的代码,比如 <div>Hello</div>,但浏览器却能正常运行它,这是怎么回事?"

这个问题的核心在于:React 并没有真的让我们直接写 HTML,而是使用了一种叫 JSX 的语法扩展。而让浏览器能够理解这段"HTML式代码"的幕后英雄,是 Babel。


二、JSX 是什么?它是怎么来的?

2.1 JSX 简介

JSX(JavaScript XML)是一种 JavaScript 的语法扩展,允许我们在 JS 文件中像写 HTML 一样编写结构代码。

例如:

jsx 复制代码
const element = <h1>Hello, world!</h1>;

这行代码看起来像是 HTML,但它其实是 JavaScript 的一种写法,最终会被转换成标准的 JavaScript 函数调用。

2.2 JSX 不是 HTML!

很多人误以为 React 可以直接写 HTML,其实不是的。我们写的 JSX 最终都会被转译为 React.createElement() 这样的函数调用。


三、Babel 是谁?它做了什么?

3.1 Babel 是一个 JavaScript 编译器

你可以把 Babel 想象成一个翻译官,它的任务是:

把你写的现代(或非标准)JavaScript 代码,翻译成浏览器可以理解的老版本 JavaScript。

比如:

  • 把 ES6 的 letconst 转换成 var
  • 把箭头函数 () => {} 转换成 function () {}
  • 把 JSX 转换成 React.createElement() 调用

3.2 Babel 如何处理 JSX?

Babel 通过插件来支持 JSX 的编译。最核心的插件就是 @babel/plugin-transform-react-jsx

当你写下这样的 JSX:

jsx 复制代码
const element = <h1>Hello, world!</h1>;

Babel 会把它转换成:

js 复制代码
const element = React.createElement('h1', null, 'Hello, world!');

是不是有点像你在用 JavaScript 创建 DOM 元素?


四、深入讲解:JSX 到底是怎么变成 JS 的?

为了更清楚地说明这个过程,我们从几个例子入手,逐步拆解。

4.1 基本元素的转换

示例 1:纯文本标签

jsx 复制代码
<h1>Hello</h1>

转换后:

js 复制代码
React.createElement('h1', null, 'Hello');

解释:

  • 'h1':表示要创建的标签名
  • null:表示没有属性
  • 'Hello':表示子节点内容

示例 2:带属性的标签

jsx 复制代码
<div className="container" id="app"></div>

转换后:

js 复制代码
React.createElement('div', { className: 'container', id: 'app' });

注意:这里没有第三个参数,因为没有子节点。

示例 3:嵌套结构

jsx 复制代码
<div>
  <h1>Hello</h1>
  <p>World</p>
</div>

转换后:

js 复制代码
React.createElement(
  'div',
  null,
  React.createElement('h1', null, 'Hello'),
  React.createElement('p', null, 'World')
);

可以看到,嵌套结构变成了多个 createElement 的嵌套调用。


五、React.createElement 到底干了什么?

既然 JSX 最终都变成了 React.createElement(),那我们就来看看这个函数到底做了什么。

5.1 函数签名

js 复制代码
React.createElement(type, [props], [...children])
  • type:可以是一个字符串(如 'div'),也可以是一个组件(如 MyComponent
  • props:对象,表示该元素的属性
  • children:子节点,可以是字符串、数字,也可以是其他通过 createElement 创建的元素

5.2 返回值

它返回的是一个描述 UI 的"虚拟 DOM 对象",结构大致如下:

js 复制代码
{
  type: 'h1',
  props: {
    children: 'Hello'
  }
}

这个对象会被 React 用来构建 Virtual DOM,并最终渲染成真实 DOM。


六、实际开发中的工具链是如何工作的?

现在我们知道,React 项目之所以能写 JSX,是因为背后有 Babel 在默默工作。那么在实际开发中,整个流程是怎样的呢?

6.1 开发环境的构建流程图

复制代码
JSX源码
   ↓
Babel(转换为原生JS)
   ↓
Webpack / Vite(打包)
   ↓
浏览器运行

也就是说,你的 JSX 文件在运行前就已经被完全转换成了标准的 JavaScript。

6.2 Create React App 中的 Babel 配置

如果你使用的是 Create React App,你并不需要手动配置 Babel。它已经内置了以下功能:

  • 支持 JSX
  • 支持最新的 JavaScript 特性
  • 自动按需引入 polyfill

当然,如果你想自定义 Babel 配置,可以通过 npm run eject 或者使用 craco 工具进行修改。


七、手写一个简单的 JSX 转换器(迷你版 Babel)

为了帮助你更好地理解整个转换过程,我们来写一个非常简化的"JSX 转 JS"转换器。

7.1 输入:

jsx 复制代码
<App>
  <Header title="首页" />
  <Content>欢迎访问</Content>
</App>

7.2 输出:

js 复制代码
React.createElement(
  App,
  null,
  React.createElement(Header, { title: "首页" }),
  React.createElement(Content, null, "欢迎访问")
);

我们可以看到,所有的 JSX 元素都被转换成了 React.createElement 调用。


八、React 17 后的变化:不需要再手动引入 React

在 React 17 之前,每个使用 JSX 的文件都需要这样开头:

js 复制代码
import React from 'react';

否则会报错:React is not defined

但从 React 17 开始,Babel 引入了新的 JSX 转换方式(叫做 runtime 自动导入),不再需要手动引入 React。

8.1 新的转换方式(无需 import React)

旧方式:

jsx 复制代码
import React from 'react';

const element = <div>Hello</div>;

新方式:

jsx 复制代码
// 不需要 import React
const element = <div>Hello</div>;

Babel 会自动将上面的代码转换为:

js 复制代码
import { jsx as _jsx } from 'react/jsx-runtime';

const element = _jsx("div", { children: "Hello" });

也就是说,React 团队把 JSX 转换的逻辑封装到了一个新的运行时模块中,从而省去了手动导入的步骤。


九、常见问题解答

9.1 为什么不能在普通 HTML 文件里直接写 JSX?

因为普通的 HTML 文件不会经过 Babel 编译,浏览器无法识别 JSX 语法,所以会报错。

9.2 我可以在 Vue 或 Angular 项目中使用 JSX 吗?

可以!Vue 和 Angular 都支持 JSX,只需要配置好 Babel 插件即可。不过它们内部并不是用 React.createElement,而是各自框架提供的创建函数。

9.3 使用 JSX 会影响性能吗?

不影响。JSX 只是在开发阶段使用的语法糖,最终都会被编译成标准的 JS,运行效率和手写 React.createElement 完全一致。


十、总结:JSX + Babel = 更加优雅的 React 开发体验

关键点 说明
JSX 是一种 JavaScript 扩展语法,用于描述 UI 结构
Babel 将 JSX 转换成 React.createElement 调用
React.createElement 构建虚拟 DOM 的基础函数
React 17+ 不再需要手动引入 React,Babel 自动处理

十一、结语

刚开始接触 React 的时候,可能你会觉得写 HTML 形式的代码很神奇,甚至怀疑浏览器是不是支持了某种新特性。

但其实这一切的背后,都是 Babel 在帮你做"翻译"。正是有了它,我们才能写出更直观、更易维护的 JSX 代码,同时又不牺牲兼容性和性能。

希望这篇文章能帮你彻底搞懂 JSX 是如何工作的,以及 Babel 在其中扮演的角色。下次再有人问你:"React 是怎么用 HTML 写 JS 的?"你就可以自信地说:

"这不是 HTML,是 JSX,是 Babel 把它翻译成了真正的 JavaScript。"

相关推荐
sunbyte4 分钟前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DoubleVerticalSlider(双垂直滑块)
前端·javascript·css·vue.js·vue
Favor_Yang8 分钟前
SQL Server通过存储过程实现HTML页面生成
前端·信息可视化·sqlserver·存储过程
中微子1 小时前
JavaScript事件循环机制:面试官最爱问的10个问题详解
前端
Eighteen Z1 小时前
CSS揭秘:10.平行四边形
前端·css·css3
拾光拾趣录1 小时前
虚拟DOM
前端·vue.js·dom
爱学习的茄子1 小时前
JavaScript事件循环深度解析:理解异步执行的本质
前端·javascript·面试
1024小神1 小时前
cocos游戏开发中多角色碰撞,物理反弹后改变方向的实现逻辑
前端·javascript
摆烂为不摆烂1 小时前
😁深入JS(五): 一文让你完全理解 hash 与 history 路由,手写前端路由
前端
1024小神1 小时前
cocos游戏开发中,如何制作一个空气墙
前端·javascript
爱编程的喵1 小时前
深入理解JavaScript事件循环机制:从同步到异步的完整解析
前端·javascript