最近初学webpack,想学着写个loader出来,结果发现里面的基础只是就是AST(抽象语法树)。它是什么,通俗来说是一种树结构,然后把js语句拆分成一个个零件,放入这棵树中。我们可以修改这棵树的节点,做些调整,再组装起来,就会变成另外的js语句了。
而AST当中有许多的对象,下面例举些本文会说到的一些对象,方便理解:
FunctionDeclaration
自定义函数声明节点Identifier
自定义标识符节点blockStatement
自定义块语句节点ReturnStatement
自定义返回语句节点BinaryExpression
自定义二进制表达式节点variableDeclaration
自定义变量声明节点variableDeclarator
自定义变量声明符节点functionExpression
自定义函数表达式节点
参考:AST对象
我们先来看这么一个函数:
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
解析图:
上面都是我们自己说的,那该怎么去看呢。有个神器包recast。官网上正好有我们上面的demo演示。
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)
可以看到打印出来:
有兴趣大家可以试试打印add里面的body继续一层层挖掘看看。
那么我们如何将add这个函数变为匿名式函数说明: const add = function(a,b){return a+b;}
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)