为什么 JSX 语法这么香?

科技公元 工具 2022-06-24

前言

时下虽然接入 JSX 语法的框架(React、Vue)越来越多,但与之缘分最深的毫无疑问仍然是 React。2013 年,当 React 带着 JSX 横空出世时,社区曾对 JSX 有过不少的争议,但如今,越来越多的人面对 JSX 都要说上一句“真香”!典型的“真香”系列。

JSX 是什么?

按照 React 官方的解释,JSX 是一个 JavaScript 的语法扩展,类似于模板语法,或者说是一个类似于 XML 的 ECMAScript 语法扩展,并且具备 JavaScript 的全部功能。

这段解释可抽离两个关键点:

  • 「JavaScript 语法扩展」
  • 「具备JavaScript 的全部功能」

JSX 的定位是 JavaScript 的「语法扩展」,而不是“某个版本”,这就决定了浏览器并不会像天然支持 JavaScript 一样支持 JSX 。这就引出了一个问题 “JSX 是如何在 JavaScript 中生效的?”

JSX 语法是如何在 JavaScript 中生效的?

React

在 React 框架中,JSX 的语法是如何在 JavaScript 中生效的呢?React 官网给出的解释是,JSX 会被编译为 React.createElement(), React.createElement() 将返回一个叫作“React Element”的 JS 对象

对于 JSX 的编译是由 Babel 来完成的。

Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

当然 Babel 也具备将 JSX 转换为 JS 的能力,看一个例子:左边是我们 React 开发中写到的语法,并且包含了一段 JSX 代码。经过 Babel 转换之后,就全部变成了 JS 代码。

为什么 JSX 语法这么香?

其实如果仔细看,发现 JSX 更像是一种语法糖,通过类似模板语法的描述方式,描述函数对象。其实在 React 中并不会强制使用 JSX 语法,我们也可以使用 React.createElement 函数,例如使用 React.createElement 函数写这样一段代码。

class Test extends React.Component {
  render() {
    return React.createElement(
      "div",
      null,
      React.createElement(
        "div",
        null,
        "Hello, ",
        this.props.test
      ),
      React.createElement("div", null, "Today is a fine day.")
    );
  }
}

ReactDOM.render(
  React.createElement(Test, {
    test: "baixiaobai"
  }),
  document.getElementById("root")
);

在采用 JSX 之后,这段代码会这样写:

class Test extends React.Component {
  render() {
    return (
    	<div>
            <div>Hello, {this.props.test}</div> 
            <div>Today is a fine day.</div>
    	</div>
    );
  }
}
ReactDOM.render(
  <Test test="baixiaobai" />,
  document.getElementById('root')
);

通过对比发现,在实际功能效果一致的前提下,JSX 代码层次分明、嵌套关系清晰;而 React.createElement 代码则给人一种非常混乱的“杂糅感”,这样的代码不仅读起来不友好,写起来也费劲。

JSX 语法写出来的代码更为的简洁,而且代码结构层次更加的清晰。

JSX 语法糖允许我们开发人员像写 HTML 一样来写我们的 JS 代码。在降低学习成本的同时还提升了我们的研发效率和研发体验。

Vue

当然在 Vue 框架中也不例外的可以使用 JSX 语法,虽然 Vue 默认推荐的还是模板。

为什么默认推荐的模板语法,引用一段 Vue 官网的原话如下:

任何合乎规范的 HTML 都是合法的 Vue 模板,这也带来了一些特有的优势:

  • 对于很多习惯了 HTML 的开发者来说,模板比起 JSX 读写起来更自然。这里当然有主观偏好的成分,但如果这种区别会导致开发效率的提升,那么它就有客观的价值存在。
  • 基于 HTML 的模板使得将已有的应用逐步迁移到 Vue 更为容易。
  • 这也使得设计师和新人开发者更容易理解和参与到项目中。
  • 你甚至可以使用其他模板预处理器,比如 Pug 来书写 Vue 的模板。

有些开发者认为模板意味着需要学习额外的 DSL (Domain-Specific Language 领域特定语言) 才能进行开发——我们认为这种区别是比较肤浅的。首先,JSX 并不是没有学习成本的——它是基于 JS 之上的一套额外语法。同时,正如同熟悉 JS 的人学习 JSX 会很容易一样,熟悉 HTML 的人学习 Vue 的模板语法也是很容易的。最后,DSL 的存在使得我们可以让开发者用更少的代码做更多的事,比如 v-on 的各种修饰符,在 JSX 中实现对应的功能会需要多得多的代码。

更抽象一点来看,我们可以把组件区分为两类:一类是偏视图表现的 (presentational),一类则是偏逻辑的 (logical)。我们推荐在前者中使用模板,在后者中使用 JSX 或渲染函数。这两类组件的比例会根据应用类型的不同有所变化,但整体来说我们发现表现类的组件远远多于逻辑类组件。

例如有这样一段模板语法。

<anchored-heading :level="1">
  <span>Hello</span> world!
</anchored-heading>

使用 JSX 语法会写成这样。

render: function (h) {
  return (
    <AnchoredHeading level={1}>
      <span>Hello</span> world!
    </AnchoredHeading>
  )
}

转换为 createElement 转换的 JS 就变成了这样。

createElement(
  'anchored-heading', {
    props: {
      level: 1
    }
  }, [
    createElement('span', 'Hello'),
    ' world!'
  ]
);

但是不管是模板语法还是 JSX 语法,都不会得到浏览器纯天然的支持,这些语法最后都会被编译成相应的 h 函数(createElement函数,不泛指所有版本,在不同版本有差异)最后变成 JS 对象,这里的编译也是和 React 一样使用的 Babel 插件来完成的。

不管是 React 推崇的 JSX 语法,还是 Vue 默认的模板语法,目的都是为了让我们写出来的代码更为的简洁,而且代码接口层次更加的清晰。在降低学习成本的同时还提升了我们的研发效率和研发体验。

读到这里,相信你已经充分理解了“JSX 是 JavaScript 的一种语法扩展,它和模板语言很接近,并且具备 JavaScript 的全部功能。 ”这一定义背后的深意。

不管是 React 还是 Vue 我们都提到了一个函数 createElement,这个函数就是将我们的 JSX 映射为 DOM的。

Apipost 私有化火热进行中

评论