更多博客文章,歡迎 Star Github/Blog
Javascript 代碼的解析(Parse )步驟分為兩個階段:**詞法分析(Lexical Analysis) **和 語法分析(Syntactic Analysis)。這個步驟接收代碼并輸出 抽象語法樹,亦稱 AST。
隨著 Babel 的生態(tài)越來越完善,我們通常會使用 Babel 來幫助我們分析代碼的解析過程。Babel 使用一個基于 ESTree 并修改過的 AST,它的內(nèi)核說明文檔可以在 [這里](https://github. com/babel/babel/blob/master/doc/ast/spec. md) 找到。
在分析 Javascript 的 AST 過程中,借助于工具 AST Explorer 能幫助我們對 AST 節(jié)點有一個更好的感性認識。
為了幫助大家更好的結(jié)合實例分析,了解核心的 Babylon AST node types 組成,這里列舉了 13 個常用例子,并分別列出了對應的 AST 節(jié)點及詳細的 node types 解析。
以下所有的代碼的 AST 全部基于 Babylon7
變量聲明
代碼
let a = 'hello'
AST

VariableDeclaration
變量聲明,kind 屬性表示是什么類型的聲明,因為 ES6 引入了 const/let。
declarations 表示聲明的多個描述,因為我們可以這樣:let a = 1, b = 2;。
interface VariableDeclaration <: Declaration {
type: "VariableDeclaration";
declarations: [ VariableDeclarator ];
kind: "var";
}
VariableDeclarator
變量聲明的描述,id 表示變量名稱節(jié)點,init 表示初始值的表達式,可以為 null。
interface VariableDeclarator <: Node {
type: "VariableDeclarator";
id: Pattern;
init: Expression | null;
}
Identifier
標識符,我覺得應該是這么叫的,就是我們寫 JS 時自定義的名稱,如變量名,函數(shù)名,屬性名,都歸為標識符。相應的接口是這樣的:
interface Identifier <: Expression, Pattern {
type: "Identifier";
name: string;
}
一個標識符可能是一個表達式,或者是解構(gòu)的模式(ES6 中的解構(gòu)語法)。我們等會會看到 Expression 和 Pattern 相關(guān)的內(nèi)容的。
Literal
字面量,這里不是指 [] 或者 {} 這些,而是本身語義就代表了一個值的字面量,如 1,“hello”, true 這些,還有正則表達式(有一個擴展的 Node 來表示正則表達式),如 /\d?/。我們看一下文檔的定義:
interface Literal <: Expression {
type: "Literal";
value: string | boolean | null | number | RegExp;
}
value 這里即對應了字面量的值,我們可以看出字面量值的類型,字符串,布爾,數(shù)值,null 和正則。
二元運算表達式
代碼
let a = 3+4
AST

BinaryExpression
二元運算表達式節(jié)點,left 和 right 表示運算符左右的兩個表達式,operator 表示一個二元運算符。
interface BinaryExpression <: Expression {
type: "BinaryExpression";
operator: BinaryOperator;
left: Expression;
right: Expression;
}
BinaryOperator
二元運算符,所有值如下:
enum BinaryOperator {
"==" | "!=" | "===" | "!=="
| "<" | "<=" | ">" | ">="
| "<<" | ">>" | ">>>"
| "+" | "-" | "*" | "/" | "%"
| "|" | "^" | "&" | "in"
| "instanceof"
}
賦值表達式
代碼
這個例子會稍微復雜一點,涉及到的 Node 類型比較多。
this.state = {date: new Date()};
AST

ExpressionStatement
表達式語句節(jié)點,a = a + 1 或者 a++ 里邊會有一個 expression 屬性指向一個表達式節(jié)點對象(后邊會提及表達式)。
interface ExpressionStatement <: Statement {
type: "ExpressionStatement";
expression: Expression;
}
AssignmentExpression
賦值表達式節(jié)點,operator 屬性表示一個賦值運算符,left 和 right 是賦值運算符左右的表達式。
interface AssignmentExpression <: Expression {
type: "AssignmentExpression";
operator: AssignmentOperator;
left: Pattern | Expression;
right: Expression;
}
AssignmentOperator
賦值運算符,所有值如下:(常用的并不多)
enum AssignmentOperator {
"=" | "+=" | "-=" | "*=" | "/=" | "%="
| "<<=" | ">>=" | ">>>="
| "|=" | "^=" | "&="
}
MemberExpression
成員表達式節(jié)點,即表示引用對象成員的語句,object 是引用對象的表達式節(jié)點,property 是表示屬性名稱,computed 如果為 false,是表示 . 來引用成員,property 應該為一個 Identifier 節(jié)點,如果 computed 屬性為 true,則是 [] 來進行引用,即 property 是一個 Expression 節(jié)點,名稱是表達式的結(jié)果值。
interface MemberExpression <: Expression, Pattern {
type: "MemberExpression";
object: Expression;
property: Expression;
computed: boolean;
}
ThisExpression
表示 this。
interface ThisExpression <: Expression {
type: "ThisExpression";
}
ObjectExpression
對象表達式節(jié)點,property 屬性是一個數(shù)組,表示對象的每一個鍵值對,每一個元素都是一個屬性節(jié)點。
interface ObjectExpression <: Expression {
type: "ObjectExpression";
properties: [ Property ];
}
Property
對象表達式中的屬性節(jié)點。key 表示鍵,value 表示值,由于 ES5 語法中有 get/set 的存在,所以有一個 kind 屬性,用來表示是普通的初始化,或者是 get/set。
interface Property <: Node {
type: "Property";
key: Literal | Identifier;
value: Expression;
kind: "init" | "get" | "set";
}
NewExpression
new 表達式。
interface NewExpression <: CallExpression {
type: "NewExpression";
}
函數(shù)調(diào)用表達式
代碼
console.log(`Hello ${name}`)
AST

CallExpression
函數(shù)調(diào)用表達式,即表示了 func(1, 2) 這一類型的語句。callee 屬性是一個表達式節(jié)點,表示函數(shù),arguments 是一個數(shù)組,元素是表達式節(jié)點,表示函數(shù)參數(shù)列表。
interface CallExpression <: Expression {
type: "CallExpression";
callee: Expression;
arguments: [ Expression ];
}
TemplateLiteral
interface TemplateLiteral <: Expression {
type: "TemplateLiteral";
quasis: [ TemplateElement ];
expressions: [ Expression ];
}
TemplateElement
interface TemplateElement <: Node {
type: "TemplateElement";
tail: boolean;
value: {
cooked: string | null;
raw: string;
};
}
箭頭函數(shù)
代碼
i => i++
AST

ArrowFunctionExpression
箭頭函數(shù)表達式。
interface ArrowFunctionExpression <: Function, Expression {
type: "ArrowFunctionExpression";
body: BlockStatement | Expression;
expression: boolean;
}
UpdateExpression
update 運算表達式節(jié)點,即 ++/--,和一元運算符類似,只是 operator 指向的節(jié)點對象類型不同,這里是 update 運算符。
interface UpdateExpression <: Expression {
type: "UpdateExpression";
operator: UpdateOperator;
argument: Expression;
prefix: boolean;
}
UpdateOperator
update 運算符,值為 ++ 或 --,配合 update 表達式節(jié)點的 prefix 屬性來表示前后。
enum UpdateOperator {
"++" | "--"
}
函數(shù)聲明
代碼
function Hello(name = 'Lily'){
}
AST

FunctionDeclaration
函數(shù)聲明,和之前提到的 Function 不同的是,id 不能為 null。
interface FunctionDeclaration <: Function, Declaration {
type: "FunctionDeclaration";
id: Identifier;
}
AssignmentPattern
interface AssignmentPattern <: Pattern {
type: "AssignmentPattern";
left: Pattern;
right: Expression;
}
BlockStatement
塊語句節(jié)點,舉個例子:if (...) { // 這里是塊語句的內(nèi)容 },塊里邊可以包含多個其他的語句,所以有一個 body 屬性,是一個數(shù)組,表示了塊里邊的多個語句。
interface BlockStatement <: Statement {
type: "BlockStatement";
body: [ Statement ];
}
類聲明
代碼
class Clock extends Component{
render(){
}
}
AST
[站外圖片上傳中...(image-597960-1532005358414)]
Classes
interface Class <: Node {
id: Identifier | null;
superClass: Expression | null;
body: ClassBody;
decorators: [ Decorator ];
}
ClassBody
interface ClassBody <: Node {
type: "ClassBody";
body: [ ClassMethod | ClassPrivateMethod | ClassProperty | ClassPrivateProperty ];
}
ClassMethod
interface ClassMethod <: Function {
type: "ClassMethod";
key: Expression;
kind: "constructor" | "method" | "get" | "set";
computed: boolean;
static: boolean;
decorators: [ Decorator ];
}
if 語句
代碼
if(a === 0){
}
AST

IfStatement
if 語句節(jié)點,很常見,會帶有三個屬性,test 屬性表示 if (...) 括號中的表達式。
consequent 屬性是表示條件為 true 時的執(zhí)行語句,通常會是一個塊語句。
alternate 屬性則是用來表示 else 后跟隨的語句節(jié)點,通常也會是塊語句,但也可以又是一個 if 語句節(jié)點,即類似這樣的結(jié)構(gòu):
if (a) { //... } else if (b) { // ... }。
alternate 當然也可以為 null。
interface IfStatement <: Statement {
type: "IfStatement";
test: Expression;
consequent: Statement;
alternate: Statement | null;
}
switch 語句
代碼
switch(num){
case 0:
x = 'Sunday'
break;
default:
x = 'Weekday'
}
AST

SwitchStatement
switch 語句節(jié)點,有兩個屬性,discriminant 屬性表示 switch 語句后緊隨的表達式,通常會是一個變量,cases 屬性是一個 case 節(jié)點的數(shù)組,用來表示各個 case 語句。
interface SwitchStatement <: Statement {
type: "SwitchStatement";
discriminant: Expression;
cases: [ SwitchCase ];
}
SwitchCase
switch 的 case 節(jié)點。test 屬性代表這個 case 的判斷表達式,consequent 則是這個 case 的執(zhí)行語句。
當 test 屬性是 null 時,則是表示 default 這個 case 節(jié)點。
interface SwitchCase <: Node {
type: "SwitchCase";
test: Expression | null;
consequent: [ Statement ];
}
for 語句
代碼
for (var i = 0; i < 9; i++) {
}
AST

ForStatement
for 循環(huán)語句節(jié)點,屬性 init/test/update 分別表示了 for 語句括號中的三個表達式,初始化值,循環(huán)判斷條件,每次循環(huán)執(zhí)行的變量更新語句(init 可以是變量聲明或者表達式)。這三個屬性都可以為 null,即 for(;;){}。
body 屬性用以表示要循環(huán)執(zhí)行的語句。
interface ForStatement <: Statement {
type: "ForStatement";
init: VariableDeclaration | Expression | null;
test: Expression | null;
update: Expression | null;
body: Statement;
}
模塊引入
代碼
import React from 'react'
AST
[站外圖片上傳中...(image-7f97a0-1532005358414)]
ImportDeclaration
模塊聲明。
interface ImportDeclaration <: ModuleDeclaration {
type: "ImportDeclaration";
specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ];
source: Literal;
}
ImportDefaultSpecifier
interface ImportDefaultSpecifier <: ModuleSpecifier {
type: "ImportDefaultSpecifier";
}
模塊導出
代碼
export default Clock
AST

ExportDefaultDeclaration
interface OptFunctionDeclaration <: FunctionDeclaration {
id: Identifier | null;
}
interface OptClasDeclaration <: ClassDeclaration {
id: Identifier | null;
}
interface ExportDefaultDeclaration <: ModuleDeclaration {
type: "ExportDefaultDeclaration";
declaration: OptFunctionDeclaration | OptClassDeclaration | Expression;
}
JSX render 方法
代碼:
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
AST
