Abstract Syntax Tree 抽象语法树简介

追本溯源

在使用前端许多工具插件的时候,咱们大多知道每一个工具库、每一个插件能作什么,不过不少同窗其实并不清楚背后用到的技术,如webpack、rollup、UglifyJS、Lint等不少的工具和库的核心都是经过Abstract Syntax Tree 抽象语法树这个概念来实现对代码的检查、分析等操做的。经过了解抽象语法树这个概念,你也能够随手编写相似的工具,发现一个新的世界。javascript

Abstract Syntax Tree 抽象语法树定义

理论的知识老是有些枯燥乏味,不过客官别急,一步一步来。html

其实这些工具的原理都是经过JavaScript Parser把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,经过操纵这颗树,咱们能够精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变动等操做。前端

图片

wikipedia定义:

In computer science, an abstract syntax tree (AST), or just syntax tree, is a tree representation of the abstract syntactic structure of source code written in a programming language.java

翻译为:

在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。node

Javascript的语法是为了给开发者更好的编程而设计的,可是不适合程序的理解。因此须要转化为AST来更适合程序分析,浏览器编译器通常会把源码转化为AST来进行进一步的分析等其余操做。webpack

如下只介绍Javascript相关的抽象语法树

好比说有一段代码:web

var a = 3;
a + 5;
复制代码

那么它的抽象语法树就相似:
express

'abc'

JavaScript Parser

JavaScript Parser, 把js源码转化为抽象语法树的解析器。编程

浏览器会把js源码经过解析器转为抽象语法树,再进一步转化为字节码或直接生成机器码。浏览器

通常来讲每一个js引擎都会有本身的抽象语法树格式,Chrome的v8引擎,firefox的SpiderMonkey引擎等等,MDN提供了详细SpiderMonkey AST format的详细说明,算是业界的标准。

发展到如今可能不一样的JavaScript Parser的AST格式会不一样,或基于SpiderMonkey AST format,或从新设计本身的AST format,或基于SpiderMonkey AST format优化改进。经过优化抽象语法树,来使程序运行的更快,也是一种提升效率的方法。

经常使用的JavaScript Parser有:

Esprima
UglifyJS2
Traceur
Acorn
Shift
复制代码

在Esprima的官网有一个比较各个Parser解析速度的列表Speed Comparison。 看下来Acorn是公认的最快的。

UglifyJS2的做者本身实现了一套js的抽象语法树,用到了继承,和现有的扁平的抽象语法树都有所不一样,但做者也提供使用不一样的抽象语法树来解析代码。

AST explorer能够在线看到不一样的parser解析js代码后获得的AST。

JavaScript AST visualizer 能够在线可视化的看到AST。

生成并使用抽象语法树 经过 esprima , 把一个名字为ast的空函数的源码生成一颗AST树:

var esprima = require('esprima');
var code = 'function ast(){}';
var ast = esprima.parse(code);
复制代码

生成的抽象语法树长这样:

"type": "Program",
  "body": [
    {
      "type": "FunctionDeclaration",
      "id": {
        "type": "Identifier",
        "name": "ast",
        "range": [
          9,
          12
        ]
      },
      "params": [],
      "body": {
        "type": "BlockStatement",
        "body": [],
        "range": [
          14,
          16
        ]
      },
      "generator": false,
      "expression": false,
      "range": [
        0,
        16
      ]
    }
  ],
  "sourceType": "module",
  "range": [
    0,
    16
  ]
}
复制代码

经过 estraverse 遍历而且更新抽象语法树,把函数名称改成ast_awsome:

...
var estraverse = require('estraverse');
estraverse.traverse(ast, {
    enter: function (node) {
        node.name += "_awsome";
    }
});
复制代码

经过 escodegen 将AST从新生成为源码:

...
var escodegen = require("escodegen");
var regenerated_code = escodegen.parse(ast)
复制代码

AST三板斧:

经过 esprima 把源码转化为AST 经过 estraverse 遍历并更新AST 经过 escodegen 将AST从新生成源码 抽象语法树的用途 浏览器最早就会把源码解析为抽象语法树,对浏览器而言AST的做用很是重要。

对开发者而言,AST的做用就是能够精准的定位到代码的任何地方,它就像是是你的手术刀,对代码进行一系列的操做。

常见的几种用途:

代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等 如JSLint、JSHint对代码错误或风格的检查,发现一些潜在的错误 IDE的错误提示、格式化、高亮、自动补全等等 代码混淆压缩 UglifyJS2等 优化变动代码,改变代码结构使达到想要的结构 代码打包工具webpack、rollup等等 CommonJS、AMD、CMD、UMD等代码规范之间的转化 CoffeeScript、TypeScript、JSX等转化为原生Javascript 总结 抽象语法树在前端领域中的应用普遍,经过抽象语法树你们能够实现不少功能,发现编写工具提升效率带来的乐趣。

参考文章

Abstract syntax tree
Understanding ASTs by Building Your Own Babel Plugin
UglifyJS — why not switching to SpiderMonkey AST
A Technical Comparison of the Shift and SpiderMonkey AST Formats
SpiderMonkey Parser API
转载自 div.io/topic/1994?…, 感谢原做者

相关文章
相关标签/搜索