博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
13 个示例快速入门 JS 抽象语法树
阅读量:5945 次
发布时间:2019-06-19

本文共 8208 字,大约阅读时间需要 27 分钟。

更多博客文章,欢迎 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/letdeclarations 表示声明的多个描述,因为我们可以这样: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

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

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

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

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

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()}.

); }复制代码

AST

参考

转载于:https://juejin.im/post/5b4d759d51882519a62f5b64

你可能感兴趣的文章
爬虫基本原理
查看>>
Heritage from father
查看>>
css选择器
查看>>
使用多线程
查看>>
Django--Uploaded Files以及Handlers
查看>>
在IIS(64位)上部署WCF服务访问Oracle数据库
查看>>
个人在 laravel 开发中使用到的一些技巧(持续更新)
查看>>
iOS之KVO
查看>>
数组的代替品
查看>>
BZOJ-1878: [SDOI2009]HH的项链(莫队算法)
查看>>
Python3 定时访问网页
查看>>
两种算法解决查找子串的问题:hdu1711
查看>>
老板,让我们专注的工作【写给老板的一封信】
查看>>
LBS突围:从微信到微博
查看>>
SFB 项目经验-40-Skype for Business-呼入正常-呼出不正常
查看>>
吴忌寒江卓尔批“闪电网络”背后,是链圈和矿圈的的利益之争
查看>>
python的cls,self,classmethod,staticmethod
查看>>
应用系统中常见报表类型解析
查看>>
[Silverlight入门系列]使用MVVM模式(9): 想在ViewModel中控制Storyboard动画?
查看>>
3 项目计划
查看>>