13 个例子快速了解JS抽象语法树
Javascript 代码的解析(Parse )步骤分为两个阶段:**词法分析(Lexical Analysis) **和 语法分析(Syntactic Analysis)。这个步骤接收代码并输出 抽象语法树,亦称 AST。
随着 Babel 的生态越来越完善,我们通常会使用 Babel 来帮助我们分析代码的解析过程。Babel 使用一个基于 ESTree 并修改过的 AST,它的内核说明文档可以在 [这里](https://github. com/babel/babel/blob/master/doc/ast/spec. md) 找到。
在分析 Javascript 的 AST 过程中,借助于工具 AST Explorer 能帮助我们对 AST 节点有一个更好的感性认识。
为了帮助大家更好的结合实例分析,了解核心的 Babylon AST node types 组成,这里列举了 13 个常用例子,并分别列出了对应的 AST 节点及详细的 node types 解析。
以下所有的代码的 AST 全部基于 Babylon7
变量声明
代码
let a = 'hello'
AST
image
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
image
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
image
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
image
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
image
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
image
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
[站外图片上传中...(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
语句节点,很常见,会带有三个属性,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
image
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
image
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
[站外图片上传中...(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
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
参考
作者:Pines_Cheng
链接:https://www.jianshu.com/p/1ae5cbcd97b6
共同学习,写下你的评论
评论加载中...
作者其他优质文章