提及 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
的語法分析