We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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'
变量声明,kind 属性表示是什么类型的声明,因为 ES6 引入了 const/let。 declarations 表示声明的多个描述,因为我们可以这样:let a = 1, b = 2;。
kind
const/let
declarations
let a = 1, b = 2;
interface VariableDeclaration <: Declaration { type: "VariableDeclaration"; declarations: [ VariableDeclarator ]; kind: "var"; }
变量声明的描述,id 表示变量名称节点,init 表示初始值的表达式,可以为 null。
id
init
null
interface VariableDeclarator <: Node { type: "VariableDeclarator"; id: Pattern; init: Expression | null; }
标识符,我觉得应该是这么叫的,就是我们写 JS 时自定义的名称,如变量名,函数名,属性名,都归为标识符。相应的接口是这样的:
interface Identifier <: Expression, Pattern { type: "Identifier"; name: string; }
一个标识符可能是一个表达式,或者是解构的模式(ES6 中的解构语法)。我们等会会看到 Expression 和 Pattern 相关的内容的。
Expression
Pattern
字面量,这里不是指 [] 或者 {} 这些,而是本身语义就代表了一个值的字面量,如 1,“hello”, true 这些,还有正则表达式(有一个扩展的 Node 来表示正则表达式),如 /\d?/。我们看一下文档的定义:
[]
{}
1
“hello”
true
Node
/\d?/
interface Literal <: Expression { type: "Literal"; value: string | boolean | null | number | RegExp; }
value 这里即对应了字面量的值,我们可以看出字面量值的类型,字符串,布尔,数值,null 和正则。
value
let a = 3+4
二元运算表达式节点,left 和 right 表示运算符左右的两个表达式,operator 表示一个二元运算符。
left
right
operator
interface BinaryExpression <: Expression { type: "BinaryExpression"; operator: BinaryOperator; left: Expression; right: Expression; }
二元运算符,所有值如下:
enum BinaryOperator { "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | "in" | "instanceof" }
这个例子会稍微复杂一点,涉及到的 Node 类型比较多。
this.state = {date: new Date()};
表达式语句节点,a = a + 1 或者 a++ 里边会有一个 expression 属性指向一个表达式节点对象(后边会提及表达式)。
a = a + 1
a++
expression
interface ExpressionStatement <: Statement { type: "ExpressionStatement"; expression: Expression; }
赋值表达式节点,operator 属性表示一个赋值运算符,left 和 right 是赋值运算符左右的表达式。
interface AssignmentExpression <: Expression { type: "AssignmentExpression"; operator: AssignmentOperator; left: Pattern | Expression; right: Expression; }
赋值运算符,所有值如下:(常用的并不多)
enum AssignmentOperator { "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" }
成员表达式节点,即表示引用对象成员的语句,object 是引用对象的表达式节点,property 是表示属性名称,computed 如果为 false,是表示 . 来引用成员,property 应该为一个 Identifier 节点,如果 computed 属性为 true,则是 [] 来进行引用,即 property 是一个 Expression 节点,名称是表达式的结果值。
object
property
computed
false
.
Identifier
interface MemberExpression <: Expression, Pattern { type: "MemberExpression"; object: Expression; property: Expression; computed: boolean; }
表示 this。
this
interface ThisExpression <: Expression { type: "ThisExpression"; }
对象表达式节点,property 属性是一个数组,表示对象的每一个键值对,每一个元素都是一个属性节点。
interface ObjectExpression <: Expression { type: "ObjectExpression"; properties: [ Property ]; }
对象表达式中的属性节点。key 表示键,value 表示值,由于 ES5 语法中有 get/set 的存在,所以有一个 kind 属性,用来表示是普通的初始化,或者是 get/set。
key
get/set
interface Property <: Node { type: "Property"; key: Literal | Identifier; value: Expression; kind: "init" | "get" | "set"; }
new 表达式。
new
interface NewExpression <: CallExpression { type: "NewExpression"; }
console.log(`Hello ${name}`)
函数调用表达式,即表示了 func(1, 2) 这一类型的语句。callee 属性是一个表达式节点,表示函数,arguments 是一个数组,元素是表达式节点,表示函数参数列表。
func(1, 2)
callee
arguments
interface CallExpression <: Expression { type: "CallExpression"; callee: Expression; arguments: [ Expression ]; }
interface TemplateLiteral <: Expression { type: "TemplateLiteral"; quasis: [ TemplateElement ]; expressions: [ Expression ]; }
interface TemplateElement <: Node { type: "TemplateElement"; tail: boolean; value: { cooked: string | null; raw: string; }; }
i => i++
箭头函数表达式。
interface ArrowFunctionExpression <: Function, Expression { type: "ArrowFunctionExpression"; body: BlockStatement | Expression; expression: boolean; }
update 运算表达式节点,即 ++/--,和一元运算符类似,只是 operator 指向的节点对象类型不同,这里是 update 运算符。
++/--
interface UpdateExpression <: Expression { type: "UpdateExpression"; operator: UpdateOperator; argument: Expression; prefix: boolean; }
update 运算符,值为 ++ 或 --,配合 update 表达式节点的 prefix 属性来表示前后。
++
--
prefix
enum UpdateOperator { "++" | "--" }
function Hello(name = 'Lily'){ }
函数声明,和之前提到的 Function 不同的是,id 不能为 null。
interface FunctionDeclaration <: Function, Declaration { type: "FunctionDeclaration"; id: Identifier; }
interface AssignmentPattern <: Pattern { type: "AssignmentPattern"; left: Pattern; right: Expression; }
块语句节点,举个例子:if (...) { // 这里是块语句的内容 },块里边可以包含多个其他的语句,所以有一个 body 属性,是一个数组,表示了块里边的多个语句。
if (...) { // 这里是块语句的内容 }
body
interface BlockStatement <: Statement { type: "BlockStatement"; body: [ Statement ]; }
class Clock extends Component{ render(){ } }
interface Class <: Node { id: Identifier | null; superClass: Expression | null; body: ClassBody; decorators: [ Decorator ]; }
interface ClassBody <: Node { type: "ClassBody"; body: [ ClassMethod | ClassPrivateMethod | ClassProperty | ClassPrivateProperty ]; }
interface ClassMethod <: Function { type: "ClassMethod"; key: Expression; kind: "constructor" | "method" | "get" | "set"; computed: boolean; static: boolean; decorators: [ Decorator ]; }
if(a === 0){ }
if 语句节点,很常见,会带有三个属性,test 属性表示 if (...) 括号中的表达式。
if
test
if (...)
consequent 属性是表示条件为 true 时的执行语句,通常会是一个块语句。
consequent
alternate 属性则是用来表示 else 后跟随的语句节点,通常也会是块语句,但也可以又是一个 if 语句节点,即类似这样的结构: if (a) { //... } else if (b) { // ... }。 alternate 当然也可以为 null。
alternate
else
if (a) { //... } else if (b) { // ... }
interface IfStatement <: Statement { type: "IfStatement"; test: Expression; consequent: Statement; alternate: Statement | null; }
switch(num){ case 0: x = 'Sunday' break; default: x = 'Weekday' }
switch 语句节点,有两个属性,discriminant 属性表示 switch 语句后紧随的表达式,通常会是一个变量,cases 属性是一个 case 节点的数组,用来表示各个 case 语句。
switch
discriminant
cases
case
interface SwitchStatement <: Statement { type: "SwitchStatement"; discriminant: Expression; cases: [ SwitchCase ]; }
switch 的 case 节点。test 属性代表这个 case 的判断表达式,consequent 则是这个 case 的执行语句。
当 test 属性是 null 时,则是表示 default 这个 case 节点。
default
interface SwitchCase <: Node { type: "SwitchCase"; test: Expression | null; consequent: [ Statement ]; }
for (var i = 0; i < 9; i++) { }
for 循环语句节点,属性 init/test/update 分别表示了 for 语句括号中的三个表达式,初始化值,循环判断条件,每次循环执行的变量更新语句(init 可以是变量声明或者表达式)。这三个属性都可以为 null,即 for(;;){}。 body 属性用以表示要循环执行的语句。
for
init/test/update
for(;;){}
interface ForStatement <: Statement { type: "ForStatement"; init: VariableDeclaration | Expression | null; test: Expression | null; update: Expression | null; body: Statement; }
import React from 'react'
模块声明。
interface ImportDeclaration <: ModuleDeclaration { type: "ImportDeclaration"; specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ]; source: Literal; }
interface ImportDefaultSpecifier <: ModuleSpecifier { type: "ImportDefaultSpecifier"; }
export default Clock
interface OptFunctionDeclaration <: FunctionDeclaration { id: Identifier | null; } interface OptClasDeclaration <: ClassDeclaration { id: Identifier | null; } interface ExportDefaultDeclaration <: ModuleDeclaration { type: "ExportDefaultDeclaration"; declaration: OptFunctionDeclaration | OptClassDeclaration | Expression; }
render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); }
The text was updated successfully, but these errors were encountered:
可以授权前端指南公众号进行转载么
Sorry, something went wrong.
@nanhupatar 可以
No branches or pull requests
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
VariableDeclaration
变量声明,
kind
属性表示是什么类型的声明,因为 ES6 引入了const/let
。declarations
表示声明的多个描述,因为我们可以这样:let a = 1, b = 2;
。VariableDeclarator
变量声明的描述,
id
表示变量名称节点,init
表示初始值的表达式,可以为null
。Identifier
标识符,我觉得应该是这么叫的,就是我们写 JS 时自定义的名称,如变量名,函数名,属性名,都归为标识符。相应的接口是这样的:
一个标识符可能是一个表达式,或者是解构的模式(ES6 中的解构语法)。我们等会会看到
Expression
和Pattern
相关的内容的。Literal
字面量,这里不是指
[]
或者{}
这些,而是本身语义就代表了一个值的字面量,如1
,“hello”
,true
这些,还有正则表达式(有一个扩展的Node
来表示正则表达式),如/\d?/
。我们看一下文档的定义:value
这里即对应了字面量的值,我们可以看出字面量值的类型,字符串,布尔,数值,null
和正则。二元运算表达式
代码
AST
BinaryExpression
二元运算表达式节点,
left
和right
表示运算符左右的两个表达式,operator
表示一个二元运算符。BinaryOperator
二元运算符,所有值如下:
赋值表达式
代码
这个例子会稍微复杂一点,涉及到的 Node 类型比较多。
AST
ExpressionStatement
表达式语句节点,
a = a + 1
或者a++
里边会有一个expression
属性指向一个表达式节点对象(后边会提及表达式)。AssignmentExpression
赋值表达式节点,
operator
属性表示一个赋值运算符,left
和right
是赋值运算符左右的表达式。AssignmentOperator
赋值运算符,所有值如下:(常用的并不多)
MemberExpression
成员表达式节点,即表示引用对象成员的语句,
object
是引用对象的表达式节点,property
是表示属性名称,computed
如果为false
,是表示.
来引用成员,property
应该为一个Identifier
节点,如果computed
属性为true
,则是[]
来进行引用,即property
是一个Expression
节点,名称是表达式的结果值。ThisExpression
表示
this
。ObjectExpression
对象表达式节点,
property
属性是一个数组,表示对象的每一个键值对,每一个元素都是一个属性节点。Property
对象表达式中的属性节点。
key
表示键,value
表示值,由于 ES5 语法中有get/set
的存在,所以有一个kind
属性,用来表示是普通的初始化,或者是get/set
。NewExpression
new
表达式。函数调用表达式
代码
AST
CallExpression
函数调用表达式,即表示了
func(1, 2)
这一类型的语句。callee
属性是一个表达式节点,表示函数,arguments
是一个数组,元素是表达式节点,表示函数参数列表。TemplateLiteral
TemplateElement
箭头函数
代码
AST
ArrowFunctionExpression
箭头函数表达式。
UpdateExpression
update 运算表达式节点,即
++/--
,和一元运算符类似,只是operator
指向的节点对象类型不同,这里是 update 运算符。UpdateOperator
update 运算符,值为
++
或--
,配合 update 表达式节点的prefix
属性来表示前后。函数声明
代码
AST
FunctionDeclaration
函数声明,和之前提到的 Function 不同的是,
id
不能为null
。AssignmentPattern
BlockStatement
块语句节点,举个例子:
if (...) { // 这里是块语句的内容 }
,块里边可以包含多个其他的语句,所以有一个body
属性,是一个数组,表示了块里边的多个语句。类声明
代码
AST
Classes
ClassBody
ClassMethod
if 语句
代码
AST
IfStatement
if
语句节点,很常见,会带有三个属性,test
属性表示if (...)
括号中的表达式。consequent
属性是表示条件为true
时的执行语句,通常会是一个块语句。alternate
属性则是用来表示else
后跟随的语句节点,通常也会是块语句,但也可以又是一个if
语句节点,即类似这样的结构:if (a) { //... } else if (b) { // ... }
。alternate
当然也可以为null
。switch 语句
代码
AST
SwitchStatement
switch
语句节点,有两个属性,discriminant
属性表示switch
语句后紧随的表达式,通常会是一个变量,cases
属性是一个case
节点的数组,用来表示各个case
语句。SwitchCase
switch
的case
节点。test
属性代表这个case
的判断表达式,consequent
则是这个case
的执行语句。当
test
属性是null
时,则是表示default
这个case
节点。for 语句
代码
AST
ForStatement
for
循环语句节点,属性init/test/update
分别表示了for
语句括号中的三个表达式,初始化值,循环判断条件,每次循环执行的变量更新语句(init
可以是变量声明或者表达式)。这三个属性都可以为null
,即for(;;){}
。body
属性用以表示要循环执行的语句。模块引入
代码
AST
ImportDeclaration
模块声明。
ImportDefaultSpecifier
模块导出
代码
AST
ExportDefaultDeclaration
JSX render 方法
代码:
AST
参考
The text was updated successfully, but these errors were encountered: