AST

AST

八月 09, 2019

最近初学webpack,想学着写个loader出来,结果发现里面的基础只是就是AST(抽象语法树)。它是什么,通俗来说是一种树结构,然后把js语句拆分成一个个零件,放入这棵树中。我们可以修改这棵树的节点,做些调整,再组装起来,就会变成另外的js语句了。
而AST当中有许多的对象,下面例举些本文会说到的一些对象,方便理解:

  • FunctionDeclaration
    自定义函数声明节点

  • Identifier
    自定义标识符节点

  • blockStatement
    自定义块语句节点

  • ReturnStatement
    自定义返回语句节点

  • BinaryExpression
    自定义二进制表达式节点

  • variableDeclaration
    自定义变量声明节点

  • variableDeclarator
    自定义变量声明符节点

  • functionExpression
    自定义函数表达式节点
    参考:AST对象

我们先来看这么一个函数:

1
2
3
function add(a, b) {
return a + b
}

它在AST中是一个FunctionDeclaration对象。下来我们把它拆解成三部分:

  • add: Identifier对象
  • params: Identifier a 和 Identifier b
  • body体: BlockStatement对象,也就是{}

首先add 是一个Identifier,它没办法拆解了。
其次params我们可以拆成Identifier的a和b。
最后body里面实际是ReturnStatement对象(return),
return里面又是个BinaryExpression对象,
BinaryExpression可以拆成

  • left: Identifier a
  • operation: +
  • right: Identifier b
    解析图:
    ast.png

上面都是我们自己说的,那该怎么去看呢。有个神器包recast。官网上正好有我们上面的demo演示。

1
2
3
4
5
const recast = require("recast");
const code = `function add(a, b) {return a + b}`
const ast = recast.parse(code);
const add = ast.program.body[0]
console.log(add)

可以看到打印出来:
ast_con.png
有兴趣大家可以试试打印add里面的body继续一层层挖掘看看。

那么我们如何将add这个函数变为匿名式函数说明: const add = function(a,b){return a+b;}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const recast = require("recast");
const code = `function add(a, b) {return a + b}`
const ast = recast.parse(code);
const add = ast.program.body[0]
console.log(add)
console.log('---------------------------------------')

// 1. 定义AST中的对象
const { variableDeclaration, variableDeclarator, functionExpression } = recast.types.builders

// 2.组装
ast.program.body[0] = variableDeclaration("const", [
variableDeclarator(add.id, functionExpression(
null, // Anonymize the function expression.
add.params,
add.body
))
]);

console.log(ast.program.body[0])
const output = recast.prettyPrint(ast, { tabWidth: 2 }).code
console.log(output)