前言
之前看到一篇文章说过: 2020年后,真正高级的前端一定是得懂AST的,具备工具链开发能力的程序员。
为什么我称其为前端的终极工具?
AST的奇妙之处就在于,它可以让我们实现程序员的终极梦想:用代码来写代码,直接通过代码(字符串)层面的操作,理论上我们可以通过操作AST做到任何事情。
AST虚拟语法树
首先我们需要知道什么是AST
AST简单的说就是: 使用对象的形式来表达一行代码
代码转AST工具网站: AST explorer
我们来看一个句简单的AST
import name from './index.js'
{
"type": "ImportDeclaration", // 语句的类型
"start": 0,
"end": 31,
"loc": {},
"specifiers": [...], // 保存了{name} 部分
"importKind": "value",
"source": {...}, // 保存了'./index.js'部分
"assertions": []
}
我们可以通过这句的AST下的source找到import的文件路径 其中的specifiers保存了import的内容
AST语句的分类
AST可以分为多种类型
ImportDeclaration // import语句
VariableDeclaration // 变量声明语句
IfStatement // if/else语句
FunctionDeclaration // 函数声明
Identifier // 变量名/函数名等
...... 还有很多
案例实现 手写一个去除console.log()的脚本
这里我们使用前端人都很熟悉的babel来做AST的解析,当然也可以用市面上的其他工具
现在我们创建如下文件 需要去除文件下的console语句
//test.js
const name = '张三'
console.log(name)
// removeConsole.js
const fs = require('fs')
const parser = require('@babel/parser')// 代码转AST工具
const traverse = require('@babel/traverse').default //AST遍历器
// 读取test中的代码 使用babel/parser转为AST
const code = fs.readFileSync('./test.js', 'utf-8')
const ast = parser.parse(code, {
sourceType: 'module'
})
// 使用babel/traverse遍历AST
// 二号参数为AST的visitor 传入对应的钩子函数,每当遍历到对应的语句即执行这个钩子函数
// 我们这里的console语句是一句'ExpressionStatement' 我们使用这个钩子读取它
// 钩子函数接收path参数 path.node即为当前语句的AST
traverse(ast,{
ExpressionStatement:(path,state)=>{
const node = path.node //
}
})
我们可以通过AST Explorer看到 这句AST的 node.expression.callee.object.name 就是console。 我们可以通过这个字段来判断这句是不是console语句
判断为console语句,删除代码
// removeConsole.js
//如果name为console,则删除这行代码
traverse(ast,{
ExpressionStatement:(path,state)=>{
const name = path.node.expression.callee.object.name
if(name==='console'){
path.remove() // 通过path.remove()删除这串AST
}
}
})
还有很多操作AST语句的方法 详见@babel/types · Babel 中文网 (babeljs.cn)
将删除console的AST重新转为JS代码
// removeConsole.js
// 使用babel/generator 将AST重新转为JS代码
const generate = require('@babel/generator').default;
const jsCode = generate(ast)
console.log(jsCode)
此时的jsCode就只剩下const name = '张三' 了
结尾
大家可以展开想象 我们可以通过操作AST来实现几乎所有的操作
比如修改所有的var为let,
自己实现一个ESLint
通过脚本写下一串代码等等
实际上 我们熟知的很多工具 如webpack,esbuild等等都是通过操作AST来实现的许多功能。
当然要学好AST,除了熟悉AST的API调用之外,还需要大量的算法知识,这也是为什么AST作为前端的高级工具的原因。
本人感悟: 其实前端玩到最后,基本上就是操作字符串,而AST为我们提供了一种更稳定操作JS字符串的功能,当然如果你是正则大神也可以)。