潜台词:为什么React要用JSX?而不是用别的什么呢?
回答思路:通过 比较论证 的方式证明用 JSX 更胜一筹。
考察:
- 技术广度,深挖知识面涉及广度,对流行框架的模板方案是否知悉了解;
- 技术方案调研能力;
回答技巧:
三步走技巧:即 “一句话解释,核心概念,方案对比”的解题思路,来回答面试中“为什么 React 使用 JSX?”这类问题。
- 一句话解释 JSX。首先能一句话说清楚 JSX 到底是什么。
- 核心概念。JSX 用于解决什么问题?如何使用?
- 方案对比。与其他的方案对比,说明 React 选用 JSX 的必要性。
一句话解释 JSX
官方解释:JSX 是一个 JS 的语法扩展,或说是一个类似于 XML 的 ECMAScript 语法扩展。(本身没有太多语法定义,也不期望引入更多标准)核心概念
React 不强制要求使用 JSX。若没有 JSX 时,React 实现一个组件依赖于使用React.createElement
函数 。
JSX 更像是 语法糖,通过类似 XML 的描述方式,描述函数对象。
用 JSX 和不用 JSX 对比: ```typescript // 不用 JSX class Hello extends React.Component { render() {
} } ReactDOM.render( React.createElement(Hello, {toWhat: ‘World’}, null), document.getElementById(‘root’) );return React.createElement(
'div',
null,
`Hello ${this.props.toWhat}`
);
// 用 JSX class Hello extends React.Component { render() { return
Hello {this.props.toWhat}
;
}
}
ReactDOM.render(
对比发现:用 JSX 后,代码简洁,代码结构层次分明。<br />React 需将组件转化为虚拟 DOM 树,所以编写的代码,实际上是手写一颗结构树。而 XML 在树结构的描述上天生具有可读性强的优势。<br />Babel 插件将 JSX 语法转换为 `React.createELement`代码。
<a name="xf5KI"></a>
## 方案对比
<a name="S04CD"></a>
### 模板
引入了太多的概念,如:模板语法、模板指令等。<br />JSX 代码更加简洁,可读性好,更贴近 HTML。
<a name="iTwLa"></a>
### 模板字符串
结构嵌套过深时,代码结构变得更加复杂,代码提示也变得困难。
<a name="jdav8"></a>
### JXON
最终放弃 JXON 这一方案的原因是,大括号不能为元素在树中开始和结束的位置,提供很好的语法提示。
<a name="Lmm8Y"></a>
## 答题
JSX 是一个 JS 的语法扩展,结构类似 XML。<br />JSX 主要用于声明 React 元素,但 React 中并不强制使用 JSX。即使使用了 JSX,也会在构建过程中,通过 Babel 插件编译为 React.createElement。所以 JSX 更像是 React.createElement 的一种语法糖。<br />React 团队并不想引入 JavaScript 本身以外的开发体系。而是希望通过合理的关注点分离保持组件开发的纯粹性。<br />JSX 以外的三种技术方案进行对比。<br />首先是模板,React 团队认为模板不应该是开发过程中的关注点,因为引入了模板语法、模板指令等概念,是一种不佳的实现方案。<br />其次是模板字符串,模板字符串编写的结构会造成多次内部嵌套,使整个结构变得复杂,并且优化代码提示也会变得困难重重。<br />最后是 JXON,同样因为代码提示困难的原因而被放弃。<br />所以 React 最后选用了 JSX,因为 JSX 与其设计思想贴合,不需要引入过多新的概念,对编辑器的代码提示也极为友好。<br />![](https://cdn.nlark.com/yuque/0/2022/jpeg/12647972/1653862391522-03011cf4-7f40-40f6-85c4-4f9acc62addc.jpeg)
<a name="SJQNV"></a>
## 进阶
**Babel 插件如何实现 JSX 到 JS 的编译?** 在 React 面试中,这个问题很容易被追问,也经常被要求手写。<br />原理:Babel 读取代码并解析,生成 AST,再将 AST 传入插件层进行转换,在转换时就可以将 JSX 的结构转换为 React.createElement 的函数。如下代码所示:
```typescript
module.exports = function (babel) {
var t = babel.types;
return {
name: "custom-jsx-plugin",
visitor: {
JSXElement(path) {
var openingElement = path.node.openingElement;
var tagName = openingElement.name.name;
var args = [];
args.push(t.stringLiteral(tagName));
var attribs = t.nullLiteral();
args.push(attribs);
var reactIdentifier = t.identifier("React"); //object
var createElementIdentifier = t.identifier("createElement");
var callee = t.memberExpression(reactIdentifier, createElementIdentifier)
var callExpression = t.callExpression(callee, args);
callExpression.arguments = callExpression.arguments.concat(path.node.children);
path.replaceWith(callExpression, path.node);
},
},
};
};
TODO:弄清楚这段代码是如何运行起来的???
查询 Babel 的开发文档。