13 個(gè)例子快速了解JS抽象語法樹

更多博客文章,歡迎 Star Github/Blog

Javascript 代碼的解析(Parse )步驟分為兩個(gè)階段:**詞法分析(Lexical Analysis) **語法分析(Syntactic Analysis)。這個(gè)步驟接收代碼并輸出 抽象語法樹,亦稱 AST。

隨著 Babel 的生態(tài)越來越完善,我們通常會(huì)使用 Babel 來幫助我們分析代碼的解析過程。Babel 使用一個(gè)基于 ESTree 并修改過的 AST,它的內(nèi)核說明文檔可以在 [這里](https://github. com/babel/babel/blob/master/doc/ast/spec. md) 找到。

在分析 Javascript 的 AST 過程中,借助于工具 AST Explorer 能幫助我們對(duì) AST 節(jié)點(diǎn)有一個(gè)更好的感性認(rèn)識(shí)。

為了幫助大家更好的結(jié)合實(shí)例分析,了解核心的 Babylon AST node types 組成,這里列舉了 13 個(gè)常用例子,并分別列出了對(duì)應(yīng)的 AST 節(jié)點(diǎn)及詳細(xì)的 node types 解析。

以下所有的代碼的 AST 全部基于 Babylon7

變量聲明

代碼

let a  = 'hello'

AST

image

VariableDeclaration

變量聲明,kind 屬性表示是什么類型的聲明,因?yàn)?ES6 引入了 const/let。
declarations 表示聲明的多個(gè)描述,因?yàn)槲覀兛梢赃@樣:let a = 1, b = 2;。

interface VariableDeclaration <: Declaration {
    type: "VariableDeclaration";
    declarations: [ VariableDeclarator ];
    kind: "var";
}

VariableDeclarator

變量聲明的描述,id 表示變量名稱節(jié)點(diǎn),init 表示初始值的表達(dá)式,可以為 null。

interface VariableDeclarator <: Node {
    type: "VariableDeclarator";
    id: Pattern;
    init: Expression | null;
} 

Identifier

標(biāo)識(shí)符,我覺得應(yīng)該是這么叫的,就是我們寫 JS 時(shí)自定義的名稱,如變量名,函數(shù)名,屬性名,都?xì)w為標(biāo)識(shí)符。相應(yīng)的接口是這樣的:

interface Identifier <: Expression, Pattern {
    type: "Identifier";
    name: string;
}

一個(gè)標(biāo)識(shí)符可能是一個(gè)表達(dá)式,或者是解構(gòu)的模式(ES6 中的解構(gòu)語法)。我們等會(huì)會(huì)看到 ExpressionPattern 相關(guān)的內(nèi)容的。

Literal

字面量,這里不是指 [] 或者 {} 這些,而是本身語義就代表了一個(gè)值的字面量,如 1,“hello”, true 這些,還有正則表達(dá)式(有一個(gè)擴(kuò)展的 Node 來表示正則表達(dá)式),如 /\d?/。我們看一下文檔的定義:

interface Literal <: Expression {
    type: "Literal";
    value: string | boolean | null | number | RegExp;
}

value 這里即對(duì)應(yīng)了字面量的值,我們可以看出字面量值的類型,字符串,布爾,數(shù)值,null 和正則。

二元運(yùn)算表達(dá)式

代碼

let a = 3+4

AST

image

BinaryExpression

二元運(yùn)算表達(dá)式節(jié)點(diǎn),leftright 表示運(yùn)算符左右的兩個(gè)表達(dá)式,operator 表示一個(gè)二元運(yùn)算符。

interface BinaryExpression <: Expression {
    type: "BinaryExpression";
    operator: BinaryOperator;
    left: Expression;
    right: Expression;
}

BinaryOperator

二元運(yùn)算符,所有值如下:

enum BinaryOperator {
    "==" | "!=" | "===" | "!=="
         | "<" | "<=" | ">" | ">="
         | "<<" | ">>" | ">>>"
         | "+" | "-" | "*" | "/" | "%"
         | "|" | "^" | "&" | "in"
         | "instanceof"
}

賦值表達(dá)式

代碼

這個(gè)例子會(huì)稍微復(fù)雜一點(diǎn),涉及到的 Node 類型比較多。

    this.state = {date: new Date()};

AST

image

ExpressionStatement

表達(dá)式語句節(jié)點(diǎn),a = a + 1 或者 a++ 里邊會(huì)有一個(gè) expression 屬性指向一個(gè)表達(dá)式節(jié)點(diǎn)對(duì)象(后邊會(huì)提及表達(dá)式)。

interface ExpressionStatement <: Statement {
    type: "ExpressionStatement";
    expression: Expression;
}

AssignmentExpression

賦值表達(dá)式節(jié)點(diǎn),operator 屬性表示一個(gè)賦值運(yùn)算符,leftright 是賦值運(yùn)算符左右的表達(dá)式。

interface AssignmentExpression <: Expression {
    type: "AssignmentExpression";
    operator: AssignmentOperator;
    left: Pattern | Expression;
    right: Expression;
}
AssignmentOperator

賦值運(yùn)算符,所有值如下:(常用的并不多)

enum AssignmentOperator {
    "=" | "+=" | "-=" | "*=" | "/=" | "%="
        | "<<=" | ">>=" | ">>>="
        | "|=" | "^=" | "&="
}

MemberExpression

成員表達(dá)式節(jié)點(diǎn),即表示引用對(duì)象成員的語句,object 是引用對(duì)象的表達(dá)式節(jié)點(diǎn),property 是表示屬性名稱,computed 如果為 false,是表示 . 來引用成員,property 應(yīng)該為一個(gè) Identifier 節(jié)點(diǎn),如果 computed 屬性為 true,則是 [] 來進(jìn)行引用,即 property 是一個(gè) Expression 節(jié)點(diǎn),名稱是表達(dá)式的結(jié)果值。

interface MemberExpression <: Expression, Pattern {
    type: "MemberExpression";
    object: Expression;
    property: Expression;
    computed: boolean;
}

ThisExpression

表示 this

interface ThisExpression <: Expression {
    type: "ThisExpression";
}

ObjectExpression

對(duì)象表達(dá)式節(jié)點(diǎn),property 屬性是一個(gè)數(shù)組,表示對(duì)象的每一個(gè)鍵值對(duì),每一個(gè)元素都是一個(gè)屬性節(jié)點(diǎn)。

interface ObjectExpression <: Expression {
    type: "ObjectExpression";
    properties: [ Property ];
}

Property

對(duì)象表達(dá)式中的屬性節(jié)點(diǎn)。key 表示鍵,value 表示值,由于 ES5 語法中有 get/set 的存在,所以有一個(gè) kind 屬性,用來表示是普通的初始化,或者是 get/set。

interface Property <: Node {
    type: "Property";
    key: Literal | Identifier;
    value: Expression;
    kind: "init" | "get" | "set";
}

NewExpression

new 表達(dá)式。

interface NewExpression <: CallExpression {
    type: "NewExpression";
}

函數(shù)調(diào)用表達(dá)式

代碼

    console.log(`Hello ${name}`)

AST

image

CallExpression

函數(shù)調(diào)用表達(dá)式,即表示了 func(1, 2) 這一類型的語句。callee 屬性是一個(gè)表達(dá)式節(jié)點(diǎn),表示函數(shù),arguments 是一個(gè)數(shù)組,元素是表達(dá)式節(jié)點(diǎn),表示函數(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

image

ArrowFunctionExpression

箭頭函數(shù)表達(dá)式。

interface ArrowFunctionExpression <: Function, Expression {
  type: "ArrowFunctionExpression";
  body: BlockStatement | Expression;
  expression: boolean;
}

UpdateExpression

update 運(yùn)算表達(dá)式節(jié)點(diǎn),即 ++/--,和一元運(yùn)算符類似,只是 operator 指向的節(jié)點(diǎn)對(duì)象類型不同,這里是 update 運(yùn)算符。

interface UpdateExpression <: Expression {
    type: "UpdateExpression";
    operator: UpdateOperator;
    argument: Expression;
    prefix: boolean;
}
UpdateOperator

update 運(yùn)算符,值為 ++--,配合 update 表達(dá)式節(jié)點(diǎn)的 prefix 屬性來表示前后。

enum UpdateOperator {
    "++" | "--"
}

函數(shù)聲明

代碼

function Hello(name = 'Lily'){
    
}

AST

image

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é)點(diǎn),舉個(gè)例子:if (...) { // 這里是塊語句的內(nèi)容 },塊里邊可以包含多個(gè)其他的語句,所以有一個(gè) body 屬性,是一個(gè)數(shù)組,表示了塊里邊的多個(gè)語句。

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

image

IfStatement

if 語句節(jié)點(diǎn),很常見,會(huì)帶有三個(gè)屬性,test 屬性表示 if (...) 括號(hào)中的表達(dá)式。

consequent 屬性是表示條件為 true 時(shí)的執(zhí)行語句,通常會(huì)是一個(gè)塊語句。

alternate 屬性則是用來表示 else 后跟隨的語句節(jié)點(diǎn),通常也會(huì)是塊語句,但也可以又是一個(gè) if 語句節(jié)點(diǎn),即類似這樣的結(jié)構(gòu):
if (a) { //... } else if (b) { // ... }
alternate 當(dāng)然也可以為 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

image

SwitchStatement

switch 語句節(jié)點(diǎn),有兩個(gè)屬性,discriminant 屬性表示 switch 語句后緊隨的表達(dá)式,通常會(huì)是一個(gè)變量,cases 屬性是一個(gè) case 節(jié)點(diǎn)的數(shù)組,用來表示各個(gè) case 語句。

interface SwitchStatement <: Statement {
    type: "SwitchStatement";
    discriminant: Expression;
    cases: [ SwitchCase ];
}

SwitchCase

switchcase 節(jié)點(diǎn)。test 屬性代表這個(gè) case 的判斷表達(dá)式,consequent 則是這個(gè) case 的執(zhí)行語句。

當(dāng) test 屬性是 null 時(shí),則是表示 default 這個(gè) case 節(jié)點(diǎn)。

interface SwitchCase <: Node {
    type: "SwitchCase";
    test: Expression | null;
    consequent: [ Statement ];
}

for 語句

代碼

for (var i = 0; i < 9; i++) {
}

AST

image

ForStatement

for 循環(huán)語句節(jié)點(diǎn),屬性 init/test/update 分別表示了 for 語句括號(hào)中的三個(gè)表達(dá)式,初始化值,循環(huán)判斷條件,每次循環(huán)執(zhí)行的變量更新語句(init 可以是變量聲明或者表達(dá)式)。這三個(gè)屬性都可以為 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";
}

模塊導(dǎo)出

代碼

export default Clock

AST

image

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

image

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,503評(píng)論 0 13
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡(jiǎn)書還為我保存起的...
    Jenaral閱讀 3,115評(píng)論 2 9
  • ㈤ 我應(yīng)該早就預(yù)料到的。 很多時(shí)候L都不是特別會(huì)表達(dá)的人,他在我面前總會(huì)變得很笨拙。 我不知道他愛我到什么程度,聽...
    毛叁閱讀 311評(píng)論 0 0
  • 上大學(xué)以來 第一次感覺 自己真的是困成狗
    祭憶__閱讀 207評(píng)論 0 0
  • Webpack是一個(gè)模塊打包器。每一個(gè)應(yīng)用可能包含多個(gè)JS文件,JS文件之間又有依賴關(guān)系。JS文件的加載需按一定的...
    大白話閱讀 306評(píng)論 0 0

友情鏈接更多精彩內(nèi)容