JSX 与 JavaScript 的关系:从语法糖到生态系统

  • admin
  • 2025-11-18 00:53:23

Hi,我是前端人类学 (之前叫布兰妮甜)!

"JSX 既不是 HTML,也不是字符串;它只是 JavaScript 的一种更友好的写法。" ------React 官方文档

在 2025 年的前端开发语境里,JSX 几乎成了 React 的代名词。然而,很多初学者仍然把它当成"另一种语言"。本文尝试用一条清晰的脉络回答:JSX 与 JavaScript 到底是什么关系?它们如何分工、如何协同,以及在实际工程里有哪些最新实践。

文章目录

[一、血统:JSX 首先是一段合法的 JavaScript 程序](#一、血统:JSX 首先是一段合法的 JavaScript 程序)

[1.1 语法扩展,而非新语言](#1.1 语法扩展,而非新语言)

[1.2 文件扩展名只是"提示"](#1.2 文件扩展名只是“提示”)

[二、转译:从 JSX 到 JavaScript 的三次"变形"](#二、转译:从 JSX 到 JavaScript 的三次“变形”)

[2.1 经典转换:`React.createElement`](#2.1 经典转换:React.createElement)

[2.2 新 JSX Transform:React 17+ 的优化](#2.2 新 JSX Transform:React 17+ 的优化)

[2.3 TypeScript 中的 JSX 模式](#2.3 TypeScript 中的 JSX 模式)

[三、语义:JSX 让 JavaScript 获得了"声明式 UI"表达能力](#三、语义:JSX 让 JavaScript 获得了“声明式 UI”表达能力)

[3.1 声明式 vs 命令式](#3.1 声明式 vs 命令式)

[3.2 JSX 的 JavaScript 完全能力](#3.2 JSX 的 JavaScript 完全能力)

[四、边界:JSX 做不到的那些 JavaScript 事](#四、边界:JSX 做不到的那些 JavaScript 事)

[五、生态:2025 年的工程化实践清单](#五、生态:2025 年的工程化实践清单)

一、血统:JSX 首先是一段合法的 JavaScript 程序

1.1 语法扩展,而非新语言

JSX 是 ECMAScript 的 语法扩展 (syntax extension) 。按照规范,任何符合 JSX 语法的源码片段 在词法和语法层面都是合法的 JavaScript。因此:

它不会引入新的关键字,也不会破坏 var / let / const 的词法作用域规则;

所有 JavaScript 表达式在 JSX 中依旧可用(花括号 {} 内);

任何 JavaScript 运行时可以忽略 JSX 语法,直接报错或跳过(因为不认识的 AST 节点)。

1.2 文件扩展名只是"提示"

.jsx 与 .js 的差异并非规范强制,而是工程约定:

扩展名

典型用途

是否需要编译

备注

.js

普通 JavaScript、工具函数、无 JSX 的 React 组件

可选

若文件里写了 JSX,则仍需 Babel/TypeScript 处理

.jsx

包含 JSX 的 UI 组件

必须

让开发者、IDE、Linter 一眼看出"这是 JSX"

二、转译:从 JSX 到 JavaScript 的三次"变形"

浏览器、Node.js 本身并不认识 JSX,因此源码上线前需要"翻译"。当前主流工具链有 Babel、TypeScript Compiler (tsc)、esbuild、swc,它们做的事可以概括为三步:

阶段

输入

输出

工具

① 类型擦除

TSX (TypeScript + JSX)

JSX

tsc --jsx preserve

② JSX 变换

JSX

React.createElement / _jsx() 调用

Babel @babel/plugin-transform-react-jsx

③ 语法降级

ES2025

ES2015 / ES5

Babel preset-env / swc

2.1 经典转换:React.createElement

这是 React 16 及以前的默认做法:

jsx

复制代码

// 源码

function Button({ label }) {

return ;

}

// Babel 产物 (旧)

import React from 'react';

function Button({ label }) {

return React.createElement('button', null, label);

}

2.2 新 JSX Transform:React 17+ 的优化

2020 年底,React 团队引入 "新 JSX 转换":

js

复制代码

// Babel 产物 (新)

import { jsx as _jsx } from 'react/jsx-runtime';

function Button({ label }) {

return _jsx('button', { children: label });

}

带来的好处:

无需手动 import React(除非使用 Hooks);

包体更小 :每个文件减少一次 React 依赖;

运行时更快 :_jsx 内部可以跳过一些 createElement 的兼容逻辑。

2.3 TypeScript 中的 JSX 模式

tsc 提供 4 种 --jsx 选项,决定了第 ① 步的产物:

preserve:完全保留 JSX,交给 Babel 做后续;

react:直接编译成 React.createElement;

react-jsx:输出 _jsx 调用;

react-jsxdev:开发模式,额外注入调试信息。

三、语义:JSX 让 JavaScript 获得了"声明式 UI"表达能力

3.1 声明式 vs 命令式

在纯 JavaScript 里,更新 DOM 通常是命令式:

js

复制代码

const h1 = document.createElement('h1');

h1.textContent = 'Hello';

document.body.appendChild(h1);

JSX 把同样的意图声明式地写进返回值:

jsx

复制代码

function Greeting() {

return

Hello

;

}

React 负责把这段"描述"同步到真实 DOM。开发者不再关心如何更新 ,只关心长什么样。

3.2 JSX 的 JavaScript 完全能力

由于 JSX 只是语法糖,你可以在标签属性、子元素中写任意 JavaScript:

jsx

复制代码

function Card({ user }) {

return (

{`${user.name}'s

{user.posts.map(p => )}

);

}

四、边界:JSX 做不到的那些 JavaScript 事

运行时自省:JSX 编译后就变成函数调用,无法再像模板字符串那样在运行时解析 AST。

多语言语法:不能在 JSX 中直接写 Python / Rust 表达式;而 JavaScript 的 Tagged Template 可以。

非 React 世界:Vue、Svelte、Solid 都提供了自己的 JSX 适配层,但语义不尽相同;脱离框架使用 JSX 需要额外运行时。

五、生态:2025 年的工程化实践清单

场景

推荐做法

新项目

React 18 + TypeScript + Vite + SWC(或 Babel)启用 react-jsx 转换

旧项目迁移

用 npx react-codemod update-react-imports 一键移除冗余 import React

服务端渲染 (Next.js)

Next.js 14 已默认开启新 JSX Transform,无需额外配置

非 React JSX(如 Solid)

在 vite.config.ts 里替换 @vitejs/plugin-solid,对应 JSX factory 指向 solid-js/h

Lint & 格式化

ESLint @eslint/jsx + Prettier 3,确保 .jsx/.tsx 文件规则一致

JSX 是 JavaScript 的语法扩展,它通过编译期转换,把类 HTML 的声明式结构映射到 JavaScript 函数调用,从而让 React(或其他库)在运行时可以高效地构建、更新用户界面。 因此,学习 JSX 从来不意味着在"多学一门语言",而是掌握一种更贴合 UI 思维的 JavaScript 写法。