从开始学习JSX到使用VUE脚手架,一直有在用babel,只是简单的理解Babel是Js的一个编译器,能保证JS语法的版本兼容问题,没有仔细的琢磨,那么今天再对babel进行一些思考。
AST(抽象语法树)
babel就是对类似JSX这样的JS扩展语法和JS进行相互转换的编译器,当然不只针对JSX,对其他的很多种扩展语法的静态分析也可用。保证新的js语法对于低版本的一些环境不能兼容。如果想深入了解他的原理,先需要理解一个基础的概念:
abstract syntax code简称AST,翻译为抽象语法树,是源代码的抽象语法结构的树状表示,就是使用树的节点来代表语法当中的结构,这里用了抽象,所以不会针对每个代码的细节进行描述,更多的是针对语法逻辑进行描述,我们可以通过一些在线的网站来生成JS的一个语法树案例来认识它。
js代码:
function printTips() {
console.log("hello world");
}
JS语法树:
{
"type": "Program",
"start": 0,
"end": 55,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 54,
"id": {
"type": "Identifier",
"start": 9,
"end": 18,
"name": "printTips"
},
"expression": false,
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 21,
"end": 54,
"body": [
{
"type": "ExpressionStatement",
"start": 25,
"end": 52,
"expression": {
"type": "CallExpression",
"start": 25,
"end": 51,
"callee": {
"type": "MemberExpression",
"start": 25,
"end": 36,
"object": {
"type": "Identifier",
"start": 25,
"end": 32,
"name": "console"
},
"property": {
"type": "Identifier",
"start": 33,
"end": 36,
"name": "log"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "Literal",
"start": 37,
"end": 50,
"value": "hello world",
"raw": ""hello world""
}
],
"optional": false
}
}
]
}
}
],
"sourceType": "module"
}
在这里可以很清除的看到对上面简单的一个printTips函数的描述,在代码执行编译的过程当中,语法树可以作为源程序到二进制的中间表示形式,当然不同语言的语法树会有所不同。
babel原理
而babel能够实现我们最初说的维持JS代码版本一致的功能,就必须有JS高版本和低版本代码转换的能力,而转换的过程正好用到了一个AST的三方插件babylon,也就是说bable也是基于抽象语法树概念进行工作的,分解来看,babel的工作大概分为下面几个步骤:
1、解析源代码(Babylon ),就是就开发者编写的babel源代码解析成抽象语法树结构。
2、转换,基于抽象语法树结构,通过babel-traverse功能进行遍历,对不同版本带来的差异进行添加,更新,和删除。
3、生成结果代码(babel generator),然后基于修改后的抽象代码树生成最后交给浏览器解析的统一版本的JS代码。
看完上面的过程,大家不一定了解babel的原理,但是不是对JSX被解析的过程有点恍然了,对,就是这个逻辑。当然也是babel的逻辑。
当然,这也是babel的原理,本篇先聊到这里,之后我们尝试编写一个babel插件,思路会更加清晰,欢迎各位大佬多多指点。