Mastering JavaScript AST: From Basics to Real-World Code Transformations
This article introduces the concept of Abstract Syntax Trees (AST) in JavaScript, explains their purpose and generation process, and demonstrates practical examples such as removing debugger statements and enhancing console.log calls using Babel’s parser, traverse, and generator tools.
Introduction
When writing business code we rarely use an AST, so most developers are unfamiliar with it. This article teaches the fundamentals of Abstract Syntax Trees, their uses, how they are generated, and provides hands‑on examples.
Basic Knowledge
What is an AST?
In computer science, an abstract syntax tree (AST) is a tree representation of the abstract syntactic structure of source code, specifically for programming languages.
For example, the JavaScript source var tree = 'this is tree' is transformed into the following AST:
{
"type": "Program",
"start": 0,
"end": 25,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 25,
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 25,
"id": {
"type": "Identifier",
"start": 4,
"end": 8,
"name": "tree"
},
"init": {
"type": "Literal",
"start": 11,
"end": 25,
"value": "this is tree",
"raw": "'this is tree'"
}
}
],
"kind": "var"
}
],
"sourceType": "module"
}What can an AST be used for?
IDE error hints, code formatting, syntax highlighting, auto‑completion
JSLint / JSHint code style checks
Webpack, Rollup bundling
Transpiling CoffeeScript, TypeScript, JSX to native JavaScript
Vue and React template compilation
How is an AST generated?
The parsing process consists of two steps:
Lexical analysis: scans the source string and produces a list of tokens (numbers, punctuation, operators, etc.).
Syntax analysis: builds relationships between tokens to produce the AST.
Using the same example var tree = 'this is tree', lexical analysis yields tokens, and syntax analysis assembles them into the AST shown above.
Formal Understanding
Lexical Analysis
Scans the source code and generates tokens.
Syntax Analysis
Converts the token list into an AST (fields like start and end are omitted for clarity).
Informal Understanding
Disclaimer: My Chinese is barely passing; just grasp the gist.
Example: "It is a pig."
Lexical Analysis
Same token generation process, illustrated with Chinese characters.
Syntax Analysis
Tokens are assembled into an AST, shown in the image below.
JavaScript Parsers
acorn
esprima
traceur
@babel/parser
Practical Example 1: Remove debugger
function fn() {
console.log('debugger')
debugger;
}Steps:
Parse the source into an AST.
Traverse the AST, locate DebuggerStatement nodes, and delete them.
Generate JavaScript code from the transformed AST.
const parser = require('@babel/parser');
const traverse = require("@babel/traverse");
const generator = require("@babel/generator");
// source code
const code = `
function fn() {
console.log('debugger')
debugger;
}
`;
// 1. parse to AST
const ast = parser.parse(code);
// 2. transform
const visitor = {
DebuggerStatement(path) {
path.remove();
}
};
traverse.default(ast, visitor);
// 3. generate code
const result = generator.default(ast, {}, code);
console.log(result.code);The core logic resides in the visitor where path.remove() deletes the debugger node.
Practical Example 2: Enhance console.log Arguments
Original code:
function funA() {
console.log(1)
}Desired transformation adds a prefix indicating the function name:
function funA() {
console.log('from function funA:', 1)
}Steps:
Parse source to AST with @babel/parser.
Traverse AST, detect CallExpression where callee is console.log.
Insert a StringLiteral at the beginning of arguments using unshift, containing the function name.
Generate the transformed code.
const visitor = {
CallExpression(path) {
const callee = path.node.callee;
if (types.isMemberExpression(callee)) {
const { object, property } = callee;
if (types.isIdentifier(object, { name: 'console' }) && types.isIdentifier(property, { name: 'log' })) {
const parent = path.getFunctionParent();
const parentFunName = parent.node.id.name;
path.node.arguments.unshift(types.stringLiteral(`from function ${parentFunName}:`));
}
}
}
};Conclusion
Although we seldom manipulate ASTs in daily work, understanding them helps us grasp the inner workings of development tools and compilers, enabling us to build utilities that improve code efficiency. For example, an AST‑based ESLint plugin was created to validate client‑only code in an SSR project.
References
babel‑handbook (https://github.com/jamiebuilds/babel-handbook)
深入 Babel (https://juejin.im/post/6844903746804137991)
高级前端基础‑JavaScript 抽象语法树 AST (https://juejin.cn/post/6844903798347939853#heading-12)
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
WeDoctor Frontend Technology
Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
