ES6 代码转成 ES5 代码的实现思路(AST)

ES6 代码转成 ES5 代码的实现思路是什么

说到 ES6 代码转成 ES5 代码,我们肯定会想到 Babel。所以,我们可以参考 Babel 的实现方式。
那么 Babel 是如何把 ES6 转成 ES5 呢,其大致分为三步:

  • 将代码字符串解析成抽象语法树,即所谓的 AST
  • 对 AST 进行处理,在这个阶段可以对 ES6 代码进行相应转换,即转成 ES5 代码
  • 根据处理后的 AST 再生成代码字符串

那么什么是AST ?

  • AST(抽象语法树) 不依赖于具体的文法,不依赖于语言的细节,我们将源代码转化为AST后,可以对AST做很多的操作,包括一些你想不到的操作,这些操作实现了各种各样形形色色的功能,给你带进一个不一样的世界。

先来看一下把一个简单的函数转换成AST之后的样子:

// 简单函数
function square(n) {
    return n * n;
}
// 转换后的AST
{
   type: "FunctionDeclaration",
   id: {
       type: "Identifier",
       name: "square"
   },
   params: [
      {
           type: "Identifier",
           name: "n"
      }
   ],
   ...
}

从纯文本转换成树形结构的数据,每个条目和树中的节点壹壹对应。

纯文本转AST的实现

当下的编译器都做了纯文本转AST的事情。

一款编译器的编译流程是很复杂的,但我们只需要关注词法分析和语法分析,这两步是从代码生成AST的关键所在。

第一步:词法分析,也叫扫描

它读取我们的代码,然后把它们按照预定的规则合并成一个个的标识 tokens (代币)。同时,它会移除空白符、注释等。最后,整个代码将被分割进一个 tokens 列表(或者说一维数组)。

const a = 5;
// 转换成
[{value: 'const', type: 'keyword'}, {value: 'a', type: 'identifier'}, ...]

当词法分析源代码的时候,它会一个一个字母地读取代码,所以很形象地称之为扫描。当它遇到空格、操作符,或者特殊符号的时候,它会认为一个话已经完成了。

第二步:语法分析,也称解析器

它会将词法分析出来的数组转换成树形的形式,同时,验证语法。语法如果有错的话,抛出语法错误。

[{value: 'const', type: 'keyword'}, {value: 'a', type: 'identifier'}, ...]
// 语法分析后的树形形式
{
   type: "VariableDeclarator", 
   id: {
       type: "Identifier",
       name: "a"
   },
   ...
}

当生成树的时候,解析器会删除一些没必要的标识 tokens(比如:不完整的括号),因此 AST 不是 100% 与源码匹配的。

解析器100%覆盖所有代码结构生成树叫做CST(具体语法树)。

用例:代码转换之babel

babel 是一个 JavaScript 编译器。宏观来说,它分3个阶段运行代码:解析(parsing) — 将代码字符串转换成 AST抽象语法树,转译(transforming) — 对抽象语法树进行变换操作,生成(generation) — 根据变换后的抽象语法树生成新的代码字符串。

我们给 babel 一段 js 代码,它修改代码然后生成新的代码返回。它是怎么修改代码的呢?没错,它创建了 AST,遍历树,修改 tokens,最后从 AST中生成新的代码。

你可能感兴趣的:(ES6 代码转成 ES5 代码的实现思路(AST))