AST 是 Abstract Syntax Tree 的缩写,即 “形象语法树”.它是以树状的模式体现编程语言的语法结构. webpack 打包 JS 代码的时候,webpack 会在咱们的原有代码根底上新增一些代码, 例如咱们能够在打包JS 代码的时候将高级代码转为低级代码,就是通过 AST 语法树来实现的
AST在线生成地址
babel插件查看应用地址

AST生成过程由源码->词法剖析->语法分析->形象语法树
例如
let a = 1 + 2
词法剖析

  • 从左至右一个字符一个字符地读入源程序, 从中辨认出一个一个 “单词”“符号”等 读出来的就是一般的字符,没有任何编程语言的函数
  • 将剖析之后后果保留在一个词法单元数组中
单词单词符号数字符号数字
leta=1+2
[  {"type": "word", value: "let"},  {"type": "word", value: "a"},  {"type": "Punctuator", value: "="},  {"type": "Numberic", value: "1"},  {"type": "Punctuator", value: "+"},  {"type": "Numberic", value: "2"},]

之后进入词法剖析
语法分析
将单词序列组合成各类的语法短语

关键字标识符赋值运算符字面量二元运算符字面量
leta=1+2
[{  "type": "VariableDecLaration",   "content": {    {"type": "kind", "value": "let"},  // kind 示意是什么类型的申明    {"type": "Identifier", "value": "a"},  // Identifier 示意是标识符    {"type": "init", "value": "="},  // 示意初始值的表达式    {"type": "Literal", "value": "1"},  // Literal 示意是一个字面量    {"type": "operator", "value": "+"},  // operator 示意是一个二元运算符    {"type": "Literal", "value": "2"},  } }]

形象语法树

 "program": {    "type": "Program",    "start": 0,    "end": 13,    "loc": {      "start": {        "line": 1,        "column": 0      },      "end": {        "line": 1,        "column": 13      }    },    "sourceType": "module",    "interpreter": null,    "body": [      {        "type": "VariableDeclaration",        "start": 0,        "end": 13,        "loc": {          "start": {            "line": 1,            "column": 0          },          "end": {            "line": 1,            "column": 13          }        },        "declarations": [  // 这里是数组,示意能够同时申明多个变量          {            "type": "VariableDeclarator",            "start": 4,            "end": 13,            "loc": {              "start": {                "line": 1,                "column": 4              },              "end": {                "line": 1,                "column": 13              }            },            "id": {              "type": "Identifier",              "start": 4,              "end": 5,              "loc": {                "start": {                  "line": 1,                  "column": 4                },                "end": {                  "line": 1,                  "column": 5                },                "identifierName": "a"              },              "name": "a"            },            "init": {              "type": "BinaryExpression",              "start": 8,              "end": 13,              "loc": {                "start": {                  "line": 1,                  "column": 8                },                "end": {                  "line": 1,                  "column": 13                }              },              "left": {                "type": "NumericLiteral",                "start": 8,                "end": 9,                "loc": {                  "start": {                    "line": 1,                    "column": 8                  },                  "end": {                    "line": 1,                    "column": 9                  }                },                "extra": {                  "rawValue": 1,                  "raw": "1"                },                "value": 1              },              "operator": "+",              "right": {                "type": "NumericLiteral",                "start": 12,                "end": 13,                "loc": {                  "start": {                    "line": 1,                    "column": 12                  },                  "end": {                    "line": 1,                    "column": 13                  }                },                "extra": {                  "rawValue": 2,                  "raw": "2"                },                "value": 2              }            }          }        ],        "kind": "let"      }    ],    "directives": []  }

程序示例

package.json依赖

    "@babel/generator": "^7.11.6",  // 转换AST构造    "@babel/parser": "^7.11.5",  // 拆解AST树结构    "@babel/traverse": "^7.11.5",     "@babel/types": "^7.11.5",

@babel/parse生成 AST

import * as parser from '@babel/parser'const code = `let a = 1 + 2`const ast = parser.parse(code)console.log(ast)

批改语法树

通过 babel 的 traverse 模块遍历节点,找到对应节点后,通过 babel 中的 generator 模块来转换语法树为代码

import * as parser from '@babel/parser'import traverse from "@babel/traverse"import generator from '@babel/generator'const code = `let val = 1 + 2`const ast = parser.parse(code)console.log(ast)// traverse 办法能够遍历所有的语法树结点traverse(ast, {  enter(path) {  // 这个path会找到所有的node    if (path.node.type == 'Identifier') {      path.node.name = 'modify'      path.stop()    }  }})const ret = generator(ast)console.log(ret)

这里会把val批改为modify

创立语法树

通过@babel/types 模块创立语法树节点而后 push 到 body 中就能够实现语法树的手动创立,

import * as parser from '@babel/parser'import traverse from "@babel/traverse"import generator from '@babel/generator'import * as t from '@babel/types'let code = ``let ast = parser.parse(code)let left = t.NumericLiteral(1)let right = t.NumericLiteral(2)let init = t.binaryExpression("+", left, right)let id = t.identifier("add")let variable = t.variableDeclarator(id, init)let declaration = t.variableDeclaration('let', [variable])ast.program.body.push(declaration)// 转换为code let genCode = generator(ast)console.log(genCode.code)
删除语法树节点

想要删除语法节点的外围就是先遍历找到所有的节点,通过 @babel/traverse 来实现, 找到每个节点之后就能够通过具体的办法来实现增删改查操作

  • NodePath 罕用的属性
    • node: 获取以后节点
    • parent : 父节点
    • parentPath :父path
    • scope: 作用域
    • context : 上下文
  • NodePath 罕用的办法
    • get: 以后节点
    • findParent:向父节点搜查节点
    • getSibling: 获取兄弟节点
    • replaceWith: 用 AST 节点替换该节点
    • replaceWithMultiple :用多个 AST 节点替换该节点
    • insertBefore: 在节点前插入节点
    • insertAfter: 在节点后插入节点
    • remove: 删除节点
const parser = require('@babel/parser')const traverse = require('@babel/traverse').default  const generator = require('@babel/generator').defaultlet code = `  console.log('jake')  let sum = 1 + 2   let minus = 2 - 1  console.log("tom")`let ast = parser.parse(code)console.log(ast)// traverse 遍历语法树的traverse(ast, {  Identifier(path) {    if (path.node.name == 'sum') {      path.parentPath.remove()    }  }})console.log(generator(ast))

删除了sum之后