JSX语法糖本质
理解 JSX 到 JavaScript 的转换过程
问题
JSX 语法糖的本质是什么?它是如何被转换成 JavaScript 代码的?
解答
JSX 是一种 JavaScript 的语法扩展,它会被 Babel 等编译工具转换为普通的 JavaScript 函数调用。
JSX 转换示例
// JSX 写法
const element = (
<div className="container">
<h1>Hello</h1>
<p>World</p>
</div>
);
转换后的代码(React 17 之前)
// 转换为 React.createElement 调用
const element = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Hello'),
React.createElement('p', null, 'World')
);
转换后的代码(React 17+)
// 使用新的 jsx-runtime,不需要手动引入 React
import { jsx as _jsx, jsxs as _jsxs } from 'react/jsx-runtime';
const element = _jsxs('div', {
className: 'container',
children: [
_jsx('h1', { children: 'Hello' }),
_jsx('p', { children: 'World' })
]
});
React.createElement 的返回值
// createElement 返回一个普通的 JavaScript 对象(虚拟 DOM)
const element = {
type: 'div',
props: {
className: 'container',
children: [
{ type: 'h1', props: { children: 'Hello' } },
{ type: 'p', props: { children: 'World' } }
]
}
};
简易版 createElement 实现
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
// 处理子元素,文本节点转为对象
children: children.map(child =>
typeof child === 'object' ? child : createTextElement(child)
)
}
};
}
function createTextElement(text) {
return {
type: 'TEXT_ELEMENT',
props: {
nodeValue: text,
children: []
}
};
}
// 使用
const element = createElement(
'div',
{ id: 'app' },
createElement('span', null, 'Hello'),
'World'
);
console.log(JSON.stringify(element, null, 2));
组件的转换
// 函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// JSX 使用组件
const element = <Welcome name="React" />;
// 转换后:type 是函数引用而非字符串
const element = React.createElement(Welcome, { name: 'React' });
关键点
- JSX 是语法糖,最终被编译为
React.createElement()或jsx()函数调用 - 转换后返回的是普通 JavaScript 对象,即虚拟 DOM
- HTML 标签转换后 type 是字符串,组件转换后 type 是函数/类引用
- React 17+ 使用新的 jsx-runtime,无需手动
import React - 这种设计使 React 可以跨平台,虚拟 DOM 可渲染到不同目标(DOM、Native、Canvas)
目录