提及 AST 语法,不少前端小伙伴都是不陌生,可是真正使用的却少之又少,本文简单总结一下本身学习和使用 ast 的心路历程。前端
首先什么是 AST 呢?node
JavaScript 是一种解释类型语言,在执行前要经历词法分析、语法分析(AST)、代码生成 三个阶段api
词法分析:JavaScript将代码串进行分析为词法单元babel
例如代码块 var answer = 6; 会被分解成为 var、answer、=、六、;
[
{
"type": "Keyword",
"value": "var"
},
{
"type": "Identifier",
"value": "answer"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "Numeric",
"value": "6"
},
{
"type": "Punctuator",
"value": ";"
}
]
复制代码
具体的 type
值能够参考 @babel/types
官方介绍 @babel/typesmarkdown
语法分析:ide
将词法单元转为由元素嵌套组成的语法结构树,就是咱们所说的抽象语法树(abstract syntax code,AST)工具
{
"type": "File",
"start": 0,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 0
}
},
"errors": [],
"program": {
"type": "Program",
"start": 0,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 0
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 15
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 14
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 10
},
"identifierName": "answer"
},
"name": "answer"
},
"init": {
"type": "NumericLiteral",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 13
},
"end": {
"line": 1,
"column": 14
}
},
"extra": {
"rawValue": 6,
"raw": "6"
},
"value": 6
}
}
],
"kind": "var"
}
],
"directives": []
},
"comments": []
}
复制代码
其实咱们单看 body
就能够,它里面包含了咱们的语法树结构,其实里面的一些字段 start
、end
、loc
这三个值对咱们来讲基本上是没有大做用的oop
咱们能够在这一步中对源代码进行添加、更新和删除节点,学习
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
var answer = 6;
const ast = parser.parse(code);
traverse.default(ast, {
enter(path) {
if(path.isIdentifier({name: "answer"})) {
path.node.name = 'question';
}
if(path.isLiteral({value: 6})) {
path.node.value = 666;
}
},
});
const newCode = generator.default(ast, {}, code).code;
console.log('newCode: ', newCode) // newCode: var question = 666;
复制代码
咱们也能够在语法树中使用 node type 进行代码的修改ui
traverse.default(ast, {
VariableDeclarator(path) {
if(path.node.id.name ==='answer'){
path.node.init.value ='666'
}
}
});
复制代码
代码生成:
const generator = require('@babel/generator');
const newCode = generator.default(ast, {}, code).code;
console.log('newCode: ', newCode) // newCode: var question = 666;
复制代码
在前端的开发过程当中,难免的须要去开发一些代码工具,咱们经过工具能够去修改咱们的源代码,从而提高开发效率。在这个状况下,咱们就须要分析源代码、修改源代码、生产新的代码。这就会用到 AST
的语法分析