正文
(foo, bar) => foo + bar;
// 简化的 AST 表示
{
"program": {
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "ArrowFunctionExpression",
"params": [
{
"type": "Identifier",
"name": "foo"
},
{
"type": "Identifier",
"name": "bar"
}
],
"body": {
"type": "BinaryExpression",
"left": {
"type": "Identifier",
"name": "foo"
},
"operator": "+",
"right": {
"type": "Identifier",
"name": "bar"
}
}
}
}
]
}
}
我们可以使用 AST Explorer 这个工具进行在线预览与编辑;在上述的 AST 表示中,顾名思义,ArrowFunctionExpression 就表示该表达式为箭头函数表达式。该函数拥有 foo 与 bar 这两个参数,参数所属的 Identifiers 类型是没有任何子节点的变量名类型;接下来我们发现加号运算符被表示为了 BinaryExpression 类型,并且其 operator 属性设置为 +,而左右两个参数分别挂载于 left 与 right 属性下。在接下来的转化步骤中,我们即是需要对这样的抽象语法树进行转换,该步骤主要由 Babel Preset 与 Plugin 控制;Babel 内部提供了 babel-traverse 这个库来辅助进行 AST 遍历,该库还提供了一系列内置的替换与操作接口。而经过转化之后的 AST 表示如下,在实际开发中我们也常常首先对比转化前后代码的 AST 表示的不同,以了解应该进行怎样的转化操作:
// AST shortened for clarity
{
"program": {
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "Literal",
"value": "use strict"
}
},
{
"type": "ExpressionStatement",
"expression": {
"type": "FunctionExpression",
"async": false,
"params": [
{
"type": "Identifier",
"name": "foo"
},
{
"type": "Identifier",
"name": "bar"
}
],
"body": {
"type": "BlockStatement",
"body": [
{
"type": "ReturnStatement",
"argument": {
"type": "BinaryExpression",
"left": {
"type": "Identifier",
"name": "foo"
},
"operator": "+",
"right": {
"type": "Identifier",
"name": "bar"
}
}
}
]
},
"parenthesizedExpression": true
}
}
]
}
}
自定义插件
Babel 支持以观察者(Visitor)模式定义插件,我们可以在 visitor 中预设想要观察的 Babel 结点类型,然后进行操作;譬如我们需要将下述箭头函数源代码转化为 ES5 中的函数定义:
// Source Code
const func = (foo, bar) => foo + bar;