Javascript AST语法树简介

什么是 AST

  • 抽象语法树(Abstract Syntax Tree):把源代码解析成的一棵树状结构,节点代表语法结构(变量、函数、表达式等)。
  • 比源代码更结构化,去掉了空白和注释,便于静态分析、代码转换和生成。

为什么需要 AST

  • 代码静态分析(lint、类型检查)
  • 代码转换(Babel、编译、polyfill)
  • 代码重构、自动化修改
  • 代码生成(代码格式化、压缩、打包)

规范与格式

  • 常用格式:ESTree(多数 JS 解析器遵循)
  • 节点包含 type、start/end(位置)、具体字段(id、params、body 等)

常用解析器/工具

  • @babel/parser(Babel) — 支持最新语法、插件丰富
  • Esprima — 轻量、ESTree 兼容
  • Acorn — 快速、可扩展
  • @babel/traverse、estraverse — 遍历/修改 AST
  • @babel/generator / recast — 从 AST 生成代码

常见节点(示例)

  • Program, VariableDeclaration, VariableDeclarator
  • FunctionDeclaration, ArrowFunctionExpression
  • Identifier, Literal
  • ExpressionStatement, CallExpression, MemberExpression
  • BinaryExpression, ReturnStatement, IfStatement, ForStatement, BlockStatement

简单示例:原始代码 -> AST(部分)

原始代码:

const x = 1 + 2;
function f(a){ return a * 2; }

对应的 AST(简化示意,JSON 形式 JSON解析):

{
  "type": "Program",
  "body": [
    {
      "type": "VariableDeclaration",
      "kind": "const",
      "declarations": [
        {
          "type": "VariableDeclarator",
          "id": { "type": "Identifier", "name": "x" },
          "init": {
            "type": "BinaryExpression",
            "operator": "+",
            "left": { "type": "Literal", "value": 1 },
            "right": { "type": "Literal", "value": 2 }
          }
        }
      ]
    },
    {
      "type": "FunctionDeclaration",
      "id": { "type": "Identifier", "name": "f" },
      "params": [{ "type": "Identifier", "name": "a" }],
      "body": {
        "type": "BlockStatement",
        "body": [
          { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "*", "left": { "type": "Identifier", "name": "a" }, "right": { "type": "Literal", "value": 2 } } }
        ]
      }
    }
  ]
}

使用 Babel 做解析、遍历、生成(最小示例)

在 mac 终端:

npm install @babel/parser @babel/traverse @babel/generator

示例代码(Node.js):

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;

const code = `const x = 1 + 2; function f(a){ return a * 2; }`;
const ast = parser.parse(code, { sourceType: "module" });

// 遍历:把所有数字常量加 1
traverse(ast, {
  NumericLiteral(path) {
    path.node.value += 1;
  }
});

const output = generator(ast).code;
console.log(output); // const x = 2 + 3; function f(a) { return a * 3; }

实践建议

  • 优先用 Babel 或 Acorn 解析复杂现代语法
  • 使用 traverse/estraverse 做遍历和修改,generator/recast 生成代码
  • 熟悉 ESTree 节点类型和常见模式匹配(如 CallExpression、Identifier 等)

参考

  • ESTree 规范
  • @babel/parser / @babel/traverse / @babel/generator 文档
  • Esprima / Acorn 项目页

如需示例扩展(特定转换、插件写法或工具链集成),说明具体场景。

posted @ 2025-12-20 13:14  ninojiang  阅读(24)  评论(0)    收藏  举报