musicode / test

test
14 stars 1 forks source link

ECMAScript ast #2

Open musicode opened 10 years ago

musicode commented 10 years ago

esprima、estraverser、escodegen

ast (抽象语法树)用于描述一段代码的结构。

使用 esprima 可以 parse 出一段 js 代码的语法树。

作为新手,可能对语法树没有具体的概念,可以先用官方提供的 demo 感受一下。

esprima.parse(code, options) 提供了一些配置项,不传的话,默认都是 false。

{
     loc: '当你想知道节点的行列信息时设为 true',
     range: '当你需要知道节点在整段代码字符串中的索引范围时设为 true',
     tokens: '设为 true 会新增一个 tokens 数组',
     comment: '当你需要解析注释节点时,设为 true',
     tolerant: '当你需要检测代码错误时,设为 true,会新增一个 errors 数组'
}

我们用语法树一般是为了做一些事情(不然 parse 出来就放着么 -.-),比如 build 时,替换一些变量名,这时就要用到 estraverser

estraverser 是一个遍历语法树节点的工具,它的所有方法都提供一种参数格式:

{
    enter: function (node) {
        // 进入节点
    },
    leave: function (node) {
        // 离开节点
    }
}

当我们修改完节点树后,需要输出这段代码,这时就要用到 escodegen

节点类型

语法树是由一个个节点组成的,每个节点都有 type 属性。这里随便列几个:

欲知全部类型,请输出 estraverse.Syntax。

节点属性

不同类型的 node,会有不同的属性,如:

函数调用节点

{
   type: 'CallExpression',
   callee: {
       type: 'Identifier',
       name: '函数名称'
   },
   arguments: [
       // 参数节点数组
   ]
}

函数表达式节点

{
    type: 'FunctionExpression',
    id: {                           // 如果是匿名函数,id 为 null
        type: 'Identifier',
        name: '函数名称'
    },
    params: [
        {
            type: 'Identifier',
            name: '参数名称'
        },
        ...
    ],
    body: {
        type: 'BlockStatement',
        body: [
            // 函数体内的节点数组
        ]
    }
}

举了两个节点的例子应该能找到一些感觉,语法树听起来很高端,其实就是几种类型的节点,相互包含组合的关系。理顺了常见的一些节点,应该能比较快的上手。

好习惯

需要注意的是,判断节点类型,最好不要这么做:

if (node.type === 'FunctionExpression') {}

而应该使用常量,如下:

var Syntax = estraverse.Syntax;
if (node.type === Syntax.FunctionExpression) {}