为了账号安全,请及时绑定邮箱和手机立即绑定

13 个例子快速了解JS抽象语法树

标签:
JavaScript

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

webp

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 中的解构语法)。我们等会会看到 ExpressionPattern 相关的内容的。

Literal

字面量,这里不是指 [] 或者 {} 这些,而是本身语义就代表了一个值的字面量,如 1“hello”, true 这些,还有正则表达式(有一个扩展的 Node 来表示正则表达式),如 /\d?/。我们看一下文档的定义:

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

value 这里即对应了字面量的值,我们可以看出字面量值的类型,字符串,布尔,数值,null 和正则。

二元运算表达式

代码

let a = 3+4

AST

webp

image

BinaryExpression

二元运算表达式节点,leftright 表示运算符左右的两个表达式,operator 表示一个二元运算符。

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

BinaryOperator

二元运算符,所有值如下:

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

赋值表达式

代码

这个例子会稍微复杂一点,涉及到的 Node 类型比较多。

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

AST

webp

image

ExpressionStatement

表达式语句节点,a = a + 1 或者 a++ 里边会有一个 expression 属性指向一个表达式节点对象(后边会提及表达式)。

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

AssignmentExpression

赋值表达式节点,operator 属性表示一个赋值运算符,leftright 是赋值运算符左右的表达式。

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

webp

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

webp

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

webp

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

webp

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

webp

image

SwitchStatement

switch 语句节点,有两个属性,discriminant 属性表示 switch 语句后紧随的表达式,通常会是一个变量,cases 属性是一个 case 节点的数组,用来表示各个 case 语句。

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

SwitchCase

switchcase 节点。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

webp

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

webp

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

webp

image

参考



作者:Pines_Cheng
链接:https://www.jianshu.com/p/1ae5cbcd97b6


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消