JS代码解析成AST以后,类似于中间形式的json数据。经过Babel解析,里面的元素叫作节点(Node),同时 Babel也提供了很多方法去操作这些节点。通过一个案例来说明AST的基本结构,代码如下:
let obj = {
name: 'javaScriptAST',
add: function (a, b) {
return a + b + 1000
},
mul: function (a, b) {
return a * b + 1000
}
}
完整的AST树,可以在https://astexplorer.net中进行查看。
########################################################
解析后AST有很多层级,这些层级互为父子节点。接下来逐级分析这些节点:
字符串形式的type字段表示节点的类型,如上述代码中的VariableDeclaration每一种类型的节点都定义了一些附加属性,用来进一步描述该节点类型。VariableDeclaration表示这是一个变量声明语句,kind表示变量声明语句所使用的关键字,declarations指声明的具体的变量。declarations是一个数组,因为一个let关键字可以同时声明多个变量,如let a,b,c;当前只声明了一个变量obj,所以declarations只有一个成员。再来查看declarations中的内容:
declarations里面是声明的具体变量的信息,一个变量都以VariableDeclarator表示。VariableDeclarator的属性主要是id和init。id很容易理解,表示这是一个Identifier(标识符),name是obj,与原始代码一致。对于init,假如只是声明变量,没有给初始值,那么init的值为null,但在原始代码中是有初始值的,因此还要继续查看init中的内容:
在原始代码中,把对象字面量赋值给了obj,在AST中把这个称为Object Expression(对象表达式)。有对象自然就有属性,还可以有多个属性,因此 properties是一个数组,一个属性对应一个成员。接着查看 properties中的第一个属性:
type为ObjectProperty,表示该节点为对象属性。JS中的对象是由一系列的键值对(key——value)组成的。由解析后的结果可知,key是一个Identifier(标识符),名字是name。注意,对象的key也可以用字符串表示,这时key的节点类型就会变为StringLiteral(字符串字面量)。 value节点的类型为StringLiteral,具体的值是”javaScriptAST”,但在该节点中,看到了三个”javaScriptAST”。extra节点是可以删掉的,如果是十六进制字符串、 unicode字符串或者hex形式的数值,这三个值就会不一样。接着继续查看第二个属性,如下所示:
这一层显示的这些属性,前面已经介绍过了,不再赘述。关键点是 value节点,因为在原始代码中把一个函数表达式赋值给了对象的属性。查看解析后的函数:
type为 FunctionExpression(函数表达式)。函数名对应上述结构中的id节点,由于代码把一个匿名函数赋值给了obj的add属性,所以这里的id为null。函数参数对应上述结构中的 params节点,由于参数是可以有多个的,所以 params是一个数组。注意,如果没有参数,params值是一个空数组,而不是null。函数体对应上述结构中的body节点。注意,这个body节点并非数组。一般函数体都会用 BlockStatement节点包裹,BlockStatement里的body节点是多条语句,所以这个body节点是一个数组。如果函数有’use strict’标记,那么directives里面就会有相应的节点。
接着查看一下函数体中具体的语句。BlockStater里body节点的内容为:
在原始代码中,这个函数内只有一条return语句,对应这里的ReturnStatement(返回语句)。 argument是 return语句返回的内容。假如return语句没有返回内容,那么argument节点值为null。在原始代码中,return返回的是a+b+1000,AST解析成了BinaryExpression(二项式)。JS中的二元运算符都可以解析成 BinaryExpression二项式主要分为三部分:left、operator和right。可以看出是把a+b作为left,1000作为right。对于right节点,type为NumericLiteral(数值字面量),value为1000。对于left节点,依然是一个二项式,代码如下: