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?…, 感謝原做者

相關文章
相關標籤/搜索