抽象语法树(Abstract Syntax Tree)
webpack
和Lint
等很多的工具和库的核心都是通过Abstract Syntax Tree
抽象语法树这个概念来实现对代码的检查、分析等操作的
- 通过了解抽象语法树这个概念,你也可以随手编写类似的工具
抽象语法树用途
-
代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等
- 如JSLint、JSHint对代码错误或风格的检查,发现一些潜在的错误
- IDE的错误提示、格式化、高亮、自动补全等等
-
代码混淆压缩
- UglifyJS2等
-
优化变更代码,改变代码结构使达到想要的结构
- 代码打包工具webpack、rollup等等
- CommonJS、AMD、CMD、UMD等代码规范之间的转化
- CoffeeScript、TypeScript、JSX等转化为原生Javascript
抽象语法树定义
这些工具的原理都是通过JavaScript Parser
把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,通过操纵这颗树,我们可以精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变更等操作
在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。Javascript的语法是为了给开发者更好的编程而设计的,但是不适合程序的理解。所以需要转化为AST来使之更适合程序分析,浏览器编译器一般会把源码转化为AST来进行进一步的分析等其他操作。
JavaScript Parser
- JavaScript Parser,把js源码转化为抽象语法树的解析器。
- 浏览器会把js源码通过解析器转为抽象语法树,再进一步转化为字节码或直接生成机器码。
- 一般来说每个js引擎都会有自己的抽象语法树格式,Chrome的v8引擎,firefox的SpiderMonkey引擎等等,MDN提供了详细SpiderMonkey AST format的详细说明,算是业界的标准。
常用的JavaScript Parser
- esprima
- traceur
- acorn
- shift
4.2 esprima
- 通过esprima把源码转化为AST
- 通过estraverse遍历并更新AST
- 通过escodegen将AST重新生成源码
- astexplorerAST的可视化工具
接下来我们将下面代码转换成AST,然后生成先的函数newAst
let code = 'function ast(){}'; //js代码即可(字符串形式)
第一步:先安装 esprima
estraverse
escodegen
npm i esprima estraverse escodegen -D
把上面的源码转成AST
// 把源码转化为AST
let ast = esprima.parseModule(code);
console.log(ast);
打印结果如下
Module {
type: 'Program',
body:
[ FunctionDeclaration {
type: 'FunctionDeclaration',
id: [Object],
params: [],
body: [Object],
generator: false,
expression: false,
async: false } ],
sourceType: 'module' }
接下来,遍历AST 并更新AST
let indent = 0;
function padding() {
return " ".repeat(indent);
}
estraverse.traverse(ast, {
enter(node) {
//进入
console.log(padding() + node.type + "进入");
if (node.type === "FunctionDeclaration") {
node.id.name = "newAst";
}
indent += 2;
},
leave(node) {
//离开
indent -= 2;
console.log(padding() + node.type + "退出");
},
});
打印结果
Program进入
FunctionDeclaration进入
Identifier进入
Identifier退出
BlockStatement进入
BlockStatement退出
FunctionDeclaration退出
Program退出
最后,把修改后的抽象语法重新生成源代码
//把修改过后的抽象语法树重新生成源代码
let result = escodegen.generate(ast);
console.log(result);
打印后的结果
function newAst() {
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。