webpack和Lint等不少的工具和庫的核心都是經過Abstract Syntax Tree抽象語法樹這個概念來實現對代碼的檢查、分析等操做的node
這些工具的原理都是經過JavaScript Parser把代碼轉化爲一顆抽象語法樹(AST),這顆樹定義了代碼的結構,經過操縱這顆樹,咱們能夠精準的定位到聲明語句、賦值語句、運算語句等等,實現對代碼的分析、優化、變動等操做webpack
在計算機科學中,抽象語法樹(abstract syntax tree或者縮寫爲AST),或者語法樹(syntax tree),是源代碼的抽象語法結構的樹狀表現形式,這裏特指編程語言的源代碼。web
Javascript的語法是爲了給開發者更好的編程而設計的,可是不適合程序的理解。因此須要轉化爲AST來更適合程序分析,瀏覽器編譯器通常會把源碼轉化爲AST來進行進一步的分析等其餘操做。編程
// 重命名
let esprima = require('esprima');
var estraverse = require('estraverse');
var escodegen = require("escodegen");
let code = 'function ast(){}';
let ast=esprima.parse(code);
let indent=0;
function pad() {
return ' '.repeat(indent);
}
estraverse.traverse(ast,{
enter(node) {
console.log(pad()+node.type);
if(node.type == 'FunctionDeclaration'){
node.id.name = 'ast_rename';
}
indent+=2;
},
leave(node) {
indent-=2;
console.log(pad()+node.type);
}
});
let generated = escodegen.generate(ast);
console.log(generated);
複製代碼
@babel/core、babel-types瀏覽器
轉換前bash
const sum = (a,b)=>a+b
babel
轉換後編程語言
var sum = function sum(a, b) { return a + b; };
ide
代碼實現函數
let babel = require('@babel/core');
let t = require('babel-types');
const code = `const sum = (a,b)=>a+b`;
// path.node 父節點
// path.parentPath 父路徑
let transformArrowFunctions = {
visitor: {
ArrowFunctionExpression: (path, state) => {
let node = path.node;
let id = path.parent.id;
let params = node.params;
let body=t.blockStatement([
t.returnStatement(node.body)
]);
let functionExpression = t.functionExpression(id,params,body,false,false);
path.replaceWith(functionExpression);
}
}
}
const result = babel.transform(code, {
plugins: [transformArrowFunctions]
});
console.log(result.code);
複製代碼
轉換前
class Person {
constructor(name) {
this.name=name;
}
getName() {
return this.name;
}
}
複製代碼
轉換後
function Person(name) {
this.name=name;
}
Person.prototype.getName=function () {
return this.name;
}
複製代碼
實現
let babel = require('@babel/core');
let t=require('babel-types');
let source=`
class Person {
constructor(name) {
this.name=name;
}
getName() {
return this.name;
}
}
`;
let ClassPlugin={
visitor: {
ClassDeclaration(path) {
let node=path.node;
let id=node.id;
let constructorFunction = t.functionDeclaration(id,[],t.blockStatement([]),false,false);
let methods=node.body.body;
let functions = [];
methods.forEach(method => {
if (method.kind == 'constructor') {
constructorFunction = t.functionDeclaration(id,method.params,method.body,false,false);
functions.push(constructorFunction);
} else {
let memberObj=t.memberExpression(t.memberExpression(id,t.identifier('prototype')),method.key);
let memberFunction = t.functionExpression(id,method.params,method.body,false,false);
let assignment = t.assignmentExpression('=',memberObj,memberFunction);
functions.push(assignment);
}
});
if (functions.length ==1) {
path.replaceWith(functions[0]);
} else {
path.replaceWithMultiple(functions);
}
}
}
}
const result = babel.transform(source,{
plugins:[
ClassPlugin
]
});
console.log(result.code);
複製代碼