更多博客文章,欢迎 Star
JS 抽象语法树 详细讲解请看姊妹篇:
Javascript 代码的解析(Parse )步骤分为两个阶段:和 。这个步骤接收代码并输出 ,亦称 AST。
随着 Babel 的生态越来越完善,我们通常会使用 Babel 来帮助我们分析代码的解析过程。Babel 使用一个基于 并修改过的 AST,它的内核说明文档可以在 [这里](. com/babel/babel/blob/master/doc/ast/spec. md) 找到。
在分析 Javascript 的 AST 过程中,借助于工具 能帮助我们对 AST 节点有一个更好的感性认识。
为了帮助大家更好的结合实例分析,了解核心的 Babylon AST node types 组成,这里列举了 13 个常用例子,并分别列出了对应的 AST 节点及详细的 node types 解析。
以下所有的代码的 AST 全部基于
变量声明
代码
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
表示变量名称节点,init
表示初始值的表达式,可以为 null
。
interface VariableDeclarator <: Node { type: "VariableDeclarator"; id: Pattern; init: Expression | null;} 复制代码
Identifier
标识符,我觉得应该是这么叫的,就是我们写 JS 时自定义的名称,如变量名,函数名,属性名,都归为标识符。相应的接口是这样的:
interface Identifier <: Expression, Pattern { type: "Identifier"; name: string;}复制代码
一个标识符可能是一个表达式,或者是解构的模式(ES6 中的解构语法)。我们等会会看到 Expression
和 Pattern
相关的内容的。
Literal
字面量,这里不是指 []
或者 {}
这些,而是本身语义就代表了一个值的字面量,如 1
,“hello”
, true
这些,还有正则表达式(有一个扩展的 Node
来表示正则表达式),如 /\d?/
。我们看一下文档的定义:
interface Literal <: Expression { type: "Literal"; value: string | boolean | null | number | RegExp;}复制代码
value
这里即对应了字面量的值,我们可以看出字面量值的类型,字符串,布尔,数值,null
和正则。
二元运算表达式
代码
let a = 3+4复制代码
AST
BinaryExpression
二元运算表达式节点,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
表达式语句节点,a = a + 1
或者 a++
里边会有一个 expression
属性指向一个表达式节点对象(后边会提及表达式)。
interface ExpressionStatement <: Statement { type: "ExpressionStatement"; expression: Expression;}复制代码
AssignmentExpression
赋值表达式节点,operator
属性表示一个赋值运算符,left
和 right
是赋值运算符左右的表达式。
interface AssignmentExpression <: Expression { type: "AssignmentExpression"; operator: AssignmentOperator; left: Pattern | Expression; right: Expression;}复制代码
AssignmentOperator
赋值运算符,所有值如下:(常用的并不多)
enum AssignmentOperator { "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&="}复制代码
MemberExpression
成员表达式节点,即表示引用对象成员的语句,object
是引用对象的表达式节点,property
是表示属性名称,computed
如果为 false
,是表示 .
来引用成员,property
应该为一个 Identifier
节点,如果 computed
属性为 true
,则是 []
来进行引用,即 property
是一个 Expression
节点,名称是表达式的结果值。
interface MemberExpression <: Expression, Pattern { type: "MemberExpression"; object: Expression; property: Expression; computed: boolean;}复制代码
ThisExpression
表示 this
。
interface ThisExpression <: Expression { type: "ThisExpression";}复制代码
ObjectExpression
对象表达式节点,property
属性是一个数组,表示对象的每一个键值对,每一个元素都是一个属性节点。
interface ObjectExpression <: Expression { type: "ObjectExpression"; properties: [ Property ];}复制代码
Property
对象表达式中的属性节点。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";}复制代码
函数调用表达式
代码
console.log(`Hello ${name}`)复制代码
AST
CallExpression
函数调用表达式,即表示了 func(1, 2)
这一类型的语句。callee
属性是一个表达式节点,表示函数,arguments
是一个数组,元素是表达式节点,表示函数参数列表。
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; };}复制代码
箭头函数
代码
i => i++复制代码
AST
ArrowFunctionExpression
箭头函数表达式。
interface ArrowFunctionExpression <: Function, Expression { type: "ArrowFunctionExpression"; body: BlockStatement | Expression; expression: boolean;}复制代码
UpdateExpression
update 运算表达式节点,即 ++/--
,和一元运算符类似,只是 operator
指向的节点对象类型不同,这里是 update 运算符。
interface UpdateExpression <: Expression { type: "UpdateExpression"; operator: UpdateOperator; argument: Expression; prefix: boolean;}复制代码
UpdateOperator
update 运算符,值为 ++
或 --
,配合 update 表达式节点的 prefix
属性来表示前后。
enum UpdateOperator { "++" | "--"}复制代码
函数声明
代码
function Hello(name = 'Lily'){ }复制代码
AST
FunctionDeclaration
函数声明,和之前提到的 Function 不同的是,id
不能为 null
。
interface FunctionDeclaration <: Function, Declaration { type: "FunctionDeclaration"; id: Identifier;}复制代码
AssignmentPattern
interface AssignmentPattern <: Pattern { type: "AssignmentPattern"; left: Pattern; right: Expression;}复制代码
BlockStatement
块语句节点,举个例子:if (...) { // 这里是块语句的内容 }
,块里边可以包含多个其他的语句,所以有一个 body
属性,是一个数组,表示了块里边的多个语句。
interface BlockStatement <: Statement { type: "BlockStatement"; body: [ Statement ];}复制代码
类声明
代码
class Clock extends Component{ render(){ }}复制代码
AST
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
语句节点,很常见,会带有三个属性,test
属性表示 if (...)
括号中的表达式。
consequent
属性是表示条件为 true
时的执行语句,通常会是一个块语句。
alternate
属性则是用来表示 else
后跟随的语句节点,通常也会是块语句,但也可以又是一个 if
语句节点,即类似这样的结构: 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
语句节点,有两个属性,discriminant
属性表示 switch
语句后紧随的表达式,通常会是一个变量,cases
属性是一个 case
节点的数组,用来表示各个 case
语句。
interface SwitchStatement <: Statement { type: "SwitchStatement"; discriminant: Expression; cases: [ SwitchCase ];}复制代码
SwitchCase
switch
的 case
节点。test
属性代表这个 case
的判断表达式,consequent
则是这个 case
的执行语句。
当 test
属性是 null
时,则是表示 default
这个 case
节点。
interface SwitchCase <: Node { type: "SwitchCase"; test: Expression | null; consequent: [ Statement ];}复制代码
for 语句
代码
for (var i = 0; i < 9; i++) {}复制代码
AST
ForStatement
for
循环语句节点,属性 init/test/update
分别表示了 for
语句括号中的三个表达式,初始化值,循环判断条件,每次循环执行的变量更新语句(init
可以是变量声明或者表达式)。这三个属性都可以为 null
,即 for(;;){}
。 body
属性用以表示要循环执行的语句。
interface ForStatement <: Statement { type: "ForStatement"; init: VariableDeclaration | Expression | null; test: Expression | null; update: Expression | null; body: Statement;}复制代码
模块引入
代码
import React from 'react'复制代码
AST
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 (); }复制代码Hello, world!
It is {this.state.date.toLocaleTimeString()}.