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+4AST
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()};ASTimage
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";
}Newexpressionnew 表达式。
interface Newexpression <: Callexpression { type: "Newexpression";
}函数调用表达式代码 console.log(`Hello ${name}`)ASTimage
Callexpression函数调用表达式,即表示了 func(1, 2) 这一类型的语句。callee 属性是一个表达式节点,表示函数,arguments 是一个数组,元素是表达式节点,表示函数参数列表。
interface Callexpression <: expression { type: "Callexpression"; callee: expression; arguments: [ expression ];
}TemplateLiteralinterface TemplateLiteral <: expression { type: "TemplateLiteral"; quasis: [ TemplateElement ]; expressions: [ expression ];
}TemplateElementinterface 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;
}Updateexpressionupdate 运算表达式节点,即 ++/--,和一元运算符类似,只是 operator 指向的节点对象类型不同,这里是 update 运算符。
interface Updateexpression <: expression { type: "Updateexpression"; operator: UpdateOperator; argument: expression; prefix: boolean;
}UpdateOperatorupdate 运算符,值为 ++ 或 --,配合 update 表达式节点的 prefix 属性来表示前后。
enum UpdateOperator { "++" | "--"}函数声明代码function Hello(name = 'Lily'){
}ASTimage
FunctionDeclaration函数声明,和之前提到的 Function 不同的是,id 不能为 null。
interface FunctionDeclaration <: Function, Declaration { type: "FunctionDeclaration"; id: Identifier;
}AssignmentPatterninterface 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)]
Classesinterface Class <: Node { id: Identifier | null; superClass: expression | null; body: ClassBody; decorators: [ Decorator ];
}ClassBodyinterface ClassBody <: Node { type: "ClassBody"; body: [ ClassMethod | ClassPrivateMethod | ClassProperty | ClassPrivateProperty ];
}ClassMethodinterface ClassMethod <: Function { type: "ClassMethod"; key: expression; kind: "constructor" | "method" | "get" | "set"; computed: boolean; static: boolean; decorators: [ Decorator ];
}if 语句代码if(a === 0){
}ASTimage
IfStatementif 语句节点,很常见,会带有三个属性,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'}ASTimage
SwitchStatementswitch 语句节点,有两个属性,discriminant 属性表示 switch 语句后紧随的表达式,通常会是一个变量,cases 属性是一个 case 节点的数组,用来表示各个 case 语句。
interface SwitchStatement <: Statement { type: "SwitchStatement"; discriminant: expression; cases: [ SwitchCase ];
}SwitchCaseswitch 的 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++) {
}ASTimage
ForStatementfor 循环语句节点,属性 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;
}importDefaultSpecifierinterface importDefaultSpecifier <: ModuleSpecifier { type: "importDefaultSpecifier";
}模块导出代码export default ClockAST
image
ExportDefaultDeclarationinterface 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()}.
);
}ASTimage
参考babel-handbook
babylon spec.md
estree
使用 Acorn 来解析 Javascript
作者:Pines_Cheng
链接:https://www.jianshu.com/p/1ae5cbcd97b6



