For more Blog posts, welcome to Star Github/Blog

For a detailed explanation of the Javascript Abstract syntax tree, see the companion article: Front-end Advanced Javascript Abstract Syntax Tree

The Javascript code Parse step is divided into two stages: Lexical Analysis and Syntactic Analysis. This step takes the code and outputs the abstract syntax tree, also known as the AST.

As Babel’s ecology becomes more refined, we often use Babel to help us analyze the parsing process of our code. Babel using a ESTree based and modified the AST, its kernel documentation can be in [here] (https://github. com/Babel/Babel/blob/master/doc/AST/spec. Md) found.

During the analysis of Javascript AST, the tool AST Explorer can help us get a better sense of AST nodes.

To help you understand the core Babylon AST node types, 13 common examples are listed here, and the corresponding AST node and node types are analyzed in detail.

The AST of all of the following code is based on Babylon7

Variable declarations

code

let a  = 'hello'
Copy the code

AST

VariableDeclaration

Variable declarations. The kind attribute indicates what type of declaration it is, since ES6 introduced const/let. Declarations represent multiple descriptions of declarations, since we can do this: let a = 1, b = 2; .

interface VariableDeclaration <: Declaration {
    type: "VariableDeclaration";
    declarations: [ VariableDeclarator ];
    kind: "var";
}
Copy the code

VariableDeclarator

Description of a variable declaration, where id represents the variable name node and init represents an expression for the initial value, which can be null.

interface VariableDeclarator <: Node {
    type: "VariableDeclarator";
    id: Pattern;
    init: Expression | null;
} 
Copy the code

Identifier

Identifiers, I think that’s what it’s called, are the names that we define when we write JS, the names of variables, the names of functions, the names of properties, are all called identifiers. The corresponding interface looks like this:

interface Identifier <: Expression, Pattern {
    type: "Identifier";
    name: string;
}
Copy the code

An identifier may be an expression or a deconstruction pattern (deconstruction syntax in ES6). We will see Expression and Pattern later.

Literal

Literals, not [] or {}, but literals that semantically represent a value, such as 1, “hello”, true, and regular expressions (with an extended Node to represent regular expressions) such as /\d? /. Let’s look at the definition of the document:

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

Value corresponds to the literal value. We can see the literal value type, string, Boolean, numeric, NULL, and re.

Binary operation expression

code

let a = 3+4
Copy the code

AST

BinaryExpression

Binary operation expression node, left and right represent two expressions left and right of the operator, and operator represents a binary operator.

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

BinaryOperator

Binary operator, all values are as follows:

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

Assignment expression

code

This example is a little more complicated and involves more Node types.

    this.state = {date: new Date(a)};Copy the code

AST

ExpressionStatement

Expression statement nodes, where a = a+ 1 or a++ have an expression property that refers to an expression node object (we’ll talk about expressions later).

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

AssignmentExpression

Assignment expression node, the operator property represents an assignment operator, left and right are expressions around the assignment operator.

interface AssignmentExpression <: Expression {
    type: "AssignmentExpression";
    operator: AssignmentOperator;
    left: Pattern | Expression;
    right: Expression;
}
Copy the code
AssignmentOperator

Assignment operator, all values as follows :(not many commonly used)

enum AssignmentOperator {
    "=" | "+ =" | "- =" | "* =" | "/ =" | "% ="
        | "< < =" | "> > =" | "> > > ="
        | "| =" | "^ =" | "& ="
}
Copy the code

MemberExpression

A member expression node is a statement that refers to an object member, object is an expression node that refers to an object, property is an attribute name, computed, if false, means. The property should be an Identifier node, or [] if the computed property is true, that is, the property is an Expression node whose name is the resulting value of the Expression.

interface MemberExpression <: Expression, Pattern {
    type: "MemberExpression";
    object: Expression;
    property: Expression;
    computed: boolean;
}
Copy the code

ThisExpression

According to this.

interface ThisExpression <: Expression {
    type: "ThisExpression";
}
Copy the code

ObjectExpression

Object expression node. The property property is an array representing each key-value pair of the object. Each element is an attribute node.

interface ObjectExpression <: Expression {
    type: "ObjectExpression";
    properties: [ Property ];
}
Copy the code

Property

Property node in an object expression. Key represents a key, value represents a value, and since ES5 syntax has get/set, there is a kind attribute that indicates a normal initialization, or get/set.

interface Property <: Node {
    type: "Property";
    key: Literal | Identifier;
    value: Expression;
    kind: "init" | "get" | "set";
}
Copy the code

NewExpression

New expression.

interface NewExpression <: CallExpression {
    type: "NewExpression";
}
Copy the code

Function call expression

code

	console.log(`Hello ${name}`)
Copy the code

AST

CallExpression

Function call expressions that represent statements of type func(1, 2). Arguments is an array, and the element is an expression node, representing the function argument list.

interface CallExpression <: Expression {
    type: "CallExpression";
    callee: Expression;
    arguments: [ Expression ];
}
Copy the code

TemplateLiteral

interface TemplateLiteral <: Expression {
  type: "TemplateLiteral";
  quasis: [ TemplateElement ];
  expressions: [ Expression ];
}
Copy the code

TemplateElement

interface TemplateElement <: Node {
  type: "TemplateElement";
  tail: boolean;
  value: {
    cooked: string | null;
    raw: string;
  };
}
Copy the code

Arrow function

code

i => i++
Copy the code

AST

ArrowFunctionExpression

Arrow function expression.

interface ArrowFunctionExpression <: Function, Expression {
  type: "ArrowFunctionExpression";
  body: BlockStatement | Expression;
  expression: boolean;
}
Copy the code

UpdateExpression

The update expression node, ++/–, is similar to the unary operator, except that the type of node object that operator points to is the update operator.

interface UpdateExpression <: Expression {
    type: "UpdateExpression";
    operator: UpdateOperator;
    argument: Expression;
    prefix: boolean;
}
Copy the code
UpdateOperator

The update operator, with a value of ++ or –, is used with the prefix attribute of the UPDATE expression node to indicate before and after.

enum UpdateOperator {
    "+ +" | "--"
}
Copy the code

Function declaration

code

function Hello(name = 'Lily'){}Copy the code

AST

FunctionDeclaration

Function declarations, unlike Function declarations above, cannot have id null.

interface FunctionDeclaration <: Function, Declaration {
    type: "FunctionDeclaration";
    id: Identifier;
}
Copy the code

AssignmentPattern

interface AssignmentPattern <: Pattern {
  type: "AssignmentPattern";
  left: Pattern;
  right: Expression;
}
Copy the code

BlockStatement

Block statement nodes, for example: if (…) {// Here is the contents of a block}, a block can contain multiple other statements, so there is a body attribute, which is an array representing multiple statements in the block.

interface BlockStatement <: Statement {
    type: "BlockStatement";
    body: [ Statement ];
}
Copy the code

Class declaration

code

class Clock extends Component{
	render(){
    }
}
Copy the code

AST

Classes

interface Class <: Node {
  id: Identifier | null;
  superClass: Expression | null;
  body: ClassBody;
  decorators: [ Decorator ];
}
Copy the code

ClassBody

interface ClassBody <: Node {
  type: "ClassBody";
  body: [ ClassMethod | ClassPrivateMethod | ClassProperty | ClassPrivateProperty ];
}
Copy the code

ClassMethod

interface ClassMethod <: Function {
  type: "ClassMethod";
  key: Expression;
  kind: "constructor" | "method" | "get" | "set";
  computed: boolean;
  static: boolean;
  decorators: [ Decorator ];
}
Copy the code

If statement

code

if(a === 0){
}
Copy the code

AST

IfStatement

If statement nodes, typically, have three attributes, the test attribute representing if (…). Expressions in parentheses.

Possession property is an execution statement that represents a condition true, which is usually a block statement.

The alternate property is used to represent an else statement node, usually a block statement, but also an if statement node, such as if (a) {//… } else if (b) { // … }. Alternate can of course be null.

interface IfStatement <: Statement {
    type: "IfStatement";
    test: Expression;
    consequent: Statement;
    alternate: Statement | null;
}
Copy the code

A switch statement

code

switch(num){
  case 0:
    x = 'Sunday'
    break;
  default:
    x = 'Weekday'
}
Copy the code

AST

SwitchStatement

A Switch statement node has two attributes. The discriminant attribute indicates the discriminant expression immediately following a switch statement, which is usually a variable. The Cases attribute is an array of case nodes, which represents each case statement.

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

SwitchCase

Case node of the switch. The test attribute represents the judgment expression for the case, and aggressively is the execution statement for the case.

When the test property is null, it represents the default case node.

interface SwitchCase <: Node {
    type: "SwitchCase";
    test: Expression | null;
    consequent: [ Statement ];
}
Copy the code

For statement

code

for (var i = 0; i < 9; i++) {
}
Copy the code

AST

ForStatement

The for loop node, init/test/update, represents the three expressions in the parentheses of the for statement, the initialization value, the loop judgment condition, and the variable update statement (init can be a variable declaration or expression) executed each time the loop executes. All three attributes can be null, for(;;) {}. The body attribute is used to indicate the statement to loop through.

interface ForStatement <: Statement {
    type: "ForStatement";
    init: VariableDeclaration | Expression | null;
    test: Expression | null;
    update: Expression | null;
    body: Statement;
}
Copy the code

Module is introduced into

code

import React from 'react'
Copy the code

AST

ImportDeclaration

Module declaration.

interface ImportDeclaration <: ModuleDeclaration {
  type: "ImportDeclaration";
  specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ];
  source: Literal;
}
Copy the code

ImportDefaultSpecifier

interface ImportDefaultSpecifier <: ModuleSpecifier {
  type: "ImportDefaultSpecifier";
}
Copy the code

Module export

code

export default Clock
Copy the code

AST

ExportDefaultDeclaration

interface OptFunctionDeclaration <: FunctionDeclaration {
  id: Identifier | null;
}

interface OptClasDeclaration <: ClassDeclaration {
  id: Identifier | null;
}

interface ExportDefaultDeclaration <: ModuleDeclaration {
  type: "ExportDefaultDeclaration";
  declaration: OptFunctionDeclaration | OptClassDeclaration | Expression;
}
Copy the code

JSX render method

Code:

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
Copy the code

AST

reference

  • babel-handbook
  • babylon spec.md
  • estree
  • Use Acorn to parse JavaScript