文章目录
前言
最近开始接触AST
,用于解决JS代码混淆的问题。
在看@渔哥的文章,虽然目前还是有点云里雾里的。
本文总结了JS抽象语法树中常见节点及结构。
推荐使用下方网站,结合例子对照观察。
Program(程序)
结构:
{
"type": "Program",
"body": [], // 多个节点
"sourceType": "module",
"range": [] //代码起始位置
}
Identifier(标识符)
可以简单的理解为变量名,函数名,属性名
{
"type": "Identifier",
"name": "", //
"range": [] // 代码起始位置
}
例子:
a
_$0x
Literal(字面量)
可以理解为一个具体的值
结构:
{
"type": "Literal",
"value": 1, // 真实值
"raw": "1", // 字符串形式的值
"range": []
}
例子:
1
'2'
0x10
VariableDeclarator(变量声明符)
属于
declarations
中的一个元素var a = 1, b = 2;
其中
a = 1
b = 2
属于两个变量声明符
结构:
{
"type": "VariableDeclarator",
"id": Identifier, // 变量名
"init": null, // 初始化,如果声明并赋值,此处就有值,只声明未赋值则为null
"range": []
}
例子:
var a, b = 2;
Property(属性)
属于
properties
的元素键值对
由于 ES5 语法中有
get/set
的存在,所以有一个kind
属性,用来表示是普通的初始化,或者是get/set
。
结构:
{
"type": "Property",
"key": "", // 键
"computed": "",
"value": "", // 值
"kind": "init",
"method": false,
"shorthand": false,
"range": []
}
Declaration(声明)
VariableDeclaration-变量声明
声明变量
结构:
{
'type': "VariableDeclaration",
'declarations': [VariableDeclarator, VariableDeclarator...], // `具体的声明, 这是一个列表,因为可以一次性声明多个变量`
'kind': "变量修饰符,例如,var、let、const",
'range': []// 声明代码的起始位置
}
例子:
var a;
var c, b;
FunctionDeclaration-函数声明
函数的声明
结构:
{
'type': 'FunctionDeclaration',
'id': '', // 可以简单的理解为函数名
'params': [], // 参数
'body': BlockSatement // 函数的主体内容,多为块语句
'generator': false,
'expression': false,
'async': false,
'range': []
}
例子:
function func(a, b) {}
Statement(语句)
BlockStatement-块语句
代码块,简单点理解就是{}包起来的代码
结构:
{
"type": "BlockStatement",
"body": [], // 代码主体
"range": []
}
例子:
function a () {}
{}
ExpressionStatement-表达式语句
结构:
{
"type": "ExpressionStatement",
"expression": // 表达式, 例如赋值表达式
"range": []
}
IFStatement-如果语句
if 语句
if (a === 1) {}
结构:
{
'type': 'IFStatement',
'test': '', // 判断,if语句()中的内容
'consequent': '', // 结果,就是满足这个条件后,后续要执行的代码块
'alternate': '', // else 中的内容,如果没有else,则为null
'range':
}
举例:
if (a === 1) {
console.log(1);
} else {
console.log(2);
}
WhileStatement-While循环语句
结构:
{
"type": "WhileStatement",
"test": ,//
"body": BlockStatement// 循环体内的代码块
"range": []
}
例子:
while (1) {}
ForStatement-For循环语句
结构:
{
"type": "ForStatement",
"init": // 初始化, 多为变量的声明
"test": BinaryExpression // 判断
"update": UpdateExpression // 更新表达式
"range": []
}
例子:
for (var i = 0; i < p.length; i++) {
}
ReturnSatement-返回语句
结构:
{
"type": "RetuenStatement",
"argument": // 返回的值, 可以是具体的值,也可以是一个表达式
"range": []
}
例子:
function func() {
return 1;
}
Expression(表达式)
如果要执行一个表达式,必定由 语句 携带着。
AssignmentExpression-赋值表达式
给变量赋值
结构:
{
"type": "AssignmentExpression",
"operator": "=",
"left": Identifier, // 操作符左边, 多为Identifier
"right": // 操作符右边, 可能为,Identifier,Literal, FucntionExpression
"range": [] // 代码起始位置
}
例子:
a = 1;
a += 1;
a |= 1;
a ^= 2;
FunctionExpression-函数表达式
{
"type": "FunctionExpression"
"id": null
"params": [Identifier, ] // 函数的参数
"body": BlockStatement// 函数体, 就是大括号里面的代码
"generator": false,
"expression": false,
"async": false,
"range": []
}
BinaryExpression-二元表达式
结构:
{
'type': 'BinaryExpression',
'operator': '===' // 二元操作符,比较操作符, < , > , ===,+,- ...
'left': '' // 操作符的左边
'right': '' // 操作符的右边
}
MemberExpression-成员表达式
简言之,就是访问对象的某个属性,这个属性就是
成员
结构:
{
'type': 'MemberExpression',
'computed': true, // 计算, a['a']为true, a.a为false
'object': '', // 对象
'property': '', // 成员名
'range': // 代码起始位置
}
例子:
a.a
a['a']
两者对比
CallExpression-调用表达式
用于函数的调用,
结构:
{
'type': 'CallExpression',
'callee': '', // 被调用者,可以理解为被调用的方法
'arguments': [], // 传递的参数
'range': []
}
举例:
console.log(1);
此时的callee
,就是console.log
,则类型为MemberExpression
atob('a')
此时的calledd
,就是atob
,则类型为Identifier
ObjectExpression-对象表达式
结构:
{
"type": "ObjectExpression",
"properties": [Property, Property], // 属性
"range": []
}
ArrayExpression-数组表达式
结构:
{
"type": "ArrayExpression",
"elements": [], // 元素
"range": []
}
例子:
a = [1, 2]
UpdateExpression-更新运算表达式
update 运算表达式节点,即
++/--
,和一元运算符类似,只是operator
指向的节点对象类型不同,这里是 update 运算符。
结构:
{
"type": "UpdateExpression",
"operator": "++", // 或者--
"argument": ,
"prefix": false, // 运算符,是否在前面,++i则为true, i++为false
"range": []
}
例子:
i++
++i
SequenceExpression-序列表达式
结构:
{
"type": "SequenceExpression",
"expressions": [], // 包含的序列节点
"range": []
}
例子:
function func () {
var a = 1;
return a = 2, 2
}
a = 2, 2
就是序列表达式