[源碼-webpack01-前置知識] AST抽象語法樹

導(dǎo)航

[react] Hooks

[封裝01-設(shè)計模式] 設(shè)計原則 和 工廠模式(簡單抽象方法) 適配器模式 裝飾器模式
[封裝02-設(shè)計模式] 命令模式 享元模式 組合模式 代理模式

[React 從零實踐01-后臺] 代碼分割
[React 從零實踐02-后臺] 權(quán)限控制
[React 從零實踐03-后臺] 自定義hooks
[React 從零實踐04-后臺] docker-compose 部署react+egg+nginx+mysql
[React 從零實踐05-后臺] Gitlab-CI使用Docker自動化部署

[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程
[源碼] Redux React-Redux01
[源碼] axios
[源碼] koa
[源碼] vuex
[源碼-vue01] data響應(yīng)式 和 初始化渲染
[源碼-vue02] computed 響應(yīng)式 - 初始化败匹,訪問停局,更新過程
[源碼-vue03] watch 偵聽屬性 - 初始化和更新
[源碼-vue04] Vue.set 和 vm.$set
[源碼-vue05] Vue.extend

[源碼-vue06] Vue.nextTick 和 vm.$nextTick

[源碼-react01] ReactDOM.render01
[源碼-react02] 手寫hook調(diào)度-useState實現(xiàn)

[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CI

[數(shù)據(jù)結(jié)構(gòu)和算法01] 二分查找和排序

[深入01] 執(zhí)行上下文
[深入02] 原型鏈
[深入03] 繼承
[深入04] 事件循環(huán)
[深入05] 柯里化 偏函數(shù) 函數(shù)記憶
[深入06] 隱式轉(zhuǎn)換 和 運算符
[深入07] 瀏覽器緩存機制(http緩存機制)
[深入08] 前端安全
[深入09] 深淺拷貝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模塊化
[深入13] 觀察者模式 發(fā)布訂閱模式 雙向數(shù)據(jù)綁定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手寫Promise
[深入20] 手寫函數(shù)
[深入21] 數(shù)據(jù)結(jié)構(gòu)和算法 - 二分查找和排序
[深入22] js和v8垃圾回收機制
[深入23] JS設(shè)計模式 - 代理忙厌,策略双藕,單例
[深入24] Fiber
[深入25] Typescript

[前端學(xué)java01-SpringBoot實戰(zhàn)] 環(huán)境配置和HelloWorld服務(wù)
[前端學(xué)java02-SpringBoot實戰(zhàn)] mybatis + mysql 實現(xiàn)歌曲增刪改查
[前端學(xué)java03-SpringBoot實戰(zhàn)] lombok缆巧,日志郎哭,部署
[前端學(xué)java04-SpringBoot實戰(zhàn)] 靜態(tài)資源 + 攔截器 + 前后端文件上傳
[前端學(xué)java05-SpringBoot實戰(zhàn)] 常用注解 + redis實現(xiàn)統(tǒng)計功能
[前端學(xué)java06-SpringBoot實戰(zhàn)] 注入 + Swagger2 3.0 + 單元測試JUnit5
[前端學(xué)java07-SpringBoot實戰(zhàn)] IOC掃描器 + 事務(wù) + Jackson
[前端學(xué)java08-SpringBoot實戰(zhàn)總結(jié)1-7] 階段性總結(jié)
[前端學(xué)java09-SpringBoot實戰(zhàn)] 多模塊配置 + Mybatis-plus + 單多模塊打包部署
[前端學(xué)java10-SpringBoot實戰(zhàn)] bean賦值轉(zhuǎn)換 + 參數(shù)校驗 + 全局異常處理
[前端學(xué)java11-SpringSecurity] 配置 + 內(nèi)存 + 數(shù)據(jù)庫 = 三種方式實現(xiàn)RBAC
[前端學(xué)java12-SpringSecurity] JWT
[前端學(xué)java13-SpringCloud] Eureka + RestTemplate + Zuul + Ribbon

前置知識

一些單詞

abstract:抽象的
( abstract syntax tree:抽象語法樹 )

Identifier:標(biāo)識符
Punctuator :標(biāo)點符號

declaration:聲明
VariableDeclaration:變量聲明
declarator:聲明人

traverse:遍歷

expression:表達原朝,表達式
performance:性能
// while parseExpression() tries to parse a single Expression with performance in mind.
// 而parseExpression()會嘗試在考慮性能的情況下解析單個Expression

doubt:疑惑
// When in doubt, use .parse() 
// 如果有疑惑的情況休雌,請使用.parse()而不要使用.parseExpression()

Numeric:數(shù)字

一些網(wǎng)站

AST explorer 查看源碼對應(yīng)的AST和JSON結(jié)構(gòu)
esprima 可以查看詞法分詞階段生成的tokens
AST 可視化工具 查看AST可視化樹狀圖
AST 對象文檔

從javascript程序到機器可執(zhí)行的機器碼需要經(jīng)歷三個階段

  • 語法檢查:詞法分析甚牲,語法分析
  • 編譯運行
  • 總結(jié):詞法分析 -> 語法分析 -> 編譯運行

AST

abstract syntax tree:抽象語法樹
abstract:抽象的

AST應(yīng)用場景

  • 代碼 ( 語法檢測 )义郑,代碼 ( 風(fēng)格檢測 ),代碼 ( 格式化 )丈钙,代碼 ( 高亮 )非驮,代碼 ( 錯誤提示 ),代碼 ( 自動補全 )
  • eslint amd cmd
  • <font color=red> webpack 通過 babel 轉(zhuǎn)義 js 語法 </font>

AST解析過程

  • (1) 讀取js文件中的 ( <font color=red>字符流</font> )
  • (2) 通過 ( <font color=red>詞法分析</font> ) 生成 token ----------- 詞法分析也叫掃描scanner雏赦,分詞階段劫笙,token是一維數(shù)組
  • (3) 通過 ( <font color=red>語法分析</font> ) 生成 AST ------------- 語法分析也叫解析器
  • (4) 生成 ( <font color=red>機器碼</font> ) 執(zhí)行 -------------------- 編譯階段也叫編譯器

詞法分析

  • 詞法分析是將 ( <font color=red>字符流char stream</font> ) 轉(zhuǎn)換為 ( <font color=red>記號流token stream</font> )
  • <font color=red>token 是不可分割的最小單元,是一個一維數(shù)組</font>
  • ( 詞法分析 ) 也稱之為 ( 掃描scanner )
  • ( <font color=red>詞法分析器</font> ) 里的每一個 (<font color=red> 關(guān)鍵字星岗,標(biāo)識符填大,操作符,標(biāo)點符號俏橘,字符串允华,數(shù)字,布爾值,注釋符靴寂,空白字符磷蜀,空格,換行符</font> ) 等都是一個token
  • <font color=blue>token數(shù)組中百炬,每一個對象包含 ( type ) 和 ( value )</font>
  • type
  • value
    • 常見的 ( type ) 如下:
    • <font color=blue>Keyword (關(guān)鍵詞)</font>
    • <font color=blue>Identifier (標(biāo)識符)</font>
    • <font color=blue>Punctuator (標(biāo)點符號)</font>
    • <font color=blue>Numeric(數(shù)字)</font>
    • <font color=blue>String (字符串)</font>
    • <font color=blue>Boolean(布爾)</font>
    • <font color=blue>Null(空值)</font>
  • 最終代碼被分割進一個tokens列表褐隆,即一維數(shù)組
源碼1:
const add = (a, b) => {
    return a + b
}

tokens:
[
  { "type": "Keyword", "value": "const" },
  { "type": "Identifier", "value": "add" },
  { "type": "Punctuator", "value": "=" },
  { "type": "Punctuator", "value": "(" },
  { "type": "Identifier", "value": "a" },
  { "type": "Punctuator", "value": "," },
  { "type": "Identifier", "value": "b" },
  { "type": "Punctuator", "value": ")" },
  { "type": "Punctuator", "value": "=>" },
  { "type": "Punctuator", "value": "{" },
  { "type": "Keyword", "value": "return" },
  { "type": "Identifier", "value": "a" },
  { "type": "Punctuator", "value": "+" },
  { "type": "Identifier", "value": "b" },
  { "type": "Punctuator", "value": "}" }
]


---
源碼2:
const a = 1;

tokens:
[
    { "type": "Keyword","value": "const" },
    { "type": "Identifier","value": "a" },
    { "type": "Punctuator","value": "=" },
    { "type": "Numeric","value": "1" },
    { "type": "Punctuator","value": ";" }
]


說明:
(1) tokens是具有type,value屬性的對象組成的數(shù)組
(2) token是詞法分析的最小單元,不能再分解
(3) 常見的type
- keyword關(guān)鍵字
- identfier標(biāo)識符
- punctuator標(biāo)點符號
- Numeric:數(shù)字

語法分析

  • ( <font color=red>語法分析</font> ) 會將詞法分析得出的token轉(zhuǎn)化成 ( <font color=red>有語法含義</font> ) 的 ( <font color=red>抽象語法樹</font> ) 結(jié)構(gòu)
  • 同時 ( <font color=red>驗證語法</font> )剖踊,有語法錯誤則拋出語法錯誤
  • 屬性
    • 最外層包含:
      • ( <font color=red>type</font> )
      • ( <font color=red>sourceType</font> )
      • ( start )
      • ( end ) 等
      • ( <font color=red>body</font> )
        • body:是一個 ( 數(shù)組 ) 庶弃,包含多個 ( <font color=red>內(nèi)容塊對象 statement </font> ),每個內(nèi)容塊包含
          • type
          • start
          • end
          • kind
          • <font color=red>declarations</font>:乘裝變量內(nèi)容的塊德澈,這個塊也是一個數(shù)組歇攻,因為變量聲明可能聲明多個
            • type
            • start
            • end
            • <font color=red>id</font>
              • type
              • start
              • end
              • <font color=red>name</font>
  • ( statement - body數(shù)組中的對象 ) 有很多類型,比如說變量聲明圃验,函數(shù)定義掉伏,if語句缝呕,while循環(huán)澳窑,等都是一個statement
    • VariableDeclaration:變量聲明
    • FunctionDeclaration:函數(shù)定義
    • IfStatement:if語句
    • WhileStatement:while循環(huán)
源碼:
var a = 1;


AST
{
  "type": "Program",
  "start": 0,
  "end": 12,
  "body": [ // ---------------------------------------------- body表示代碼具體的內(nèi)容
    { // ---------------------------------------------------- statement內(nèi)容塊對象,一個body可能包含多個statement
      "type": "VariableDeclaration", // --------------------- 變量聲明
      "start": 0,
      "end": 10,
      "declarations": [
        { 
          "type": "VariableDeclarator", // ------------------ 變量聲明
          "start": 4,
          "end": 9,
          "id": {
            "type": "Identifier", // ------------------------- 標(biāo)識符
            "start": 4,
            "end": 5,
            "name": "a"
          },
          "init": {
            "type": "Literal",
            "start": 8,
            "end": 9,
            "value": 1,
            "raw": "1"
          }
        }
      ],
      "kind": "var" // --------------------------------------- 變量類型
    }
  ],
  "sourceType": "module"
}


說明:
(1) 最外層屬性:type供常,start摊聋,end,body[]栈暇,sourceType
- body:表示代碼的具體內(nèi)容
    - 內(nèi)容塊:body中可能包含多個內(nèi)容塊麻裁,每個內(nèi)容塊用一個對象表示
    - 內(nèi)容塊包含:
        - type
        - start
        - end
        - kind
        - declarations:乘裝變量內(nèi)容的塊,這個塊也是一個數(shù)組源祈,因為變量聲明可能生命多個
            - type
            - start
            - end
            - id
                - type
                - start
                - end
                - name 
- sourceType:表示語言的種類


(2) body是一個數(shù)組煎源,成員是statement內(nèi)容塊對象,因為body可以包含多個statement內(nèi)容塊
- statement 有很多類型香缺,比如說變量聲明手销,函數(shù)定義,if語句图张,while循環(huán)锋拖,等都是一個statement
    - VariableDeclaration:變量聲明
    - FunctionDeclaration:函數(shù)定義
    - IfStatement:if語句
    - WhileStatement:while循環(huán)
image
image
image

Babel原理

  • babel編譯的過程:<font color=red>解析parse -> 轉(zhuǎn)換transform -> 生成generate</font>
  • 解析 parse
    • <font color=red>@babel/parser</font>:將字符串轉(zhuǎn)換成AST,Babylon( 現(xiàn)在是@babel/parser ) 是 Babel 中使用的 JavaScript 解析器
    • 解析過程分為兩個階段
      • 語法分析:字符流 -> token流
      • 詞法分析:token流 -> AST
    • @babel/parser
  • 轉(zhuǎn)換 transform
    • <font color=red>@babel/traverse</font>:主要用于遍歷AST
      • Babel接收解析得到的AST并通過 ( babel-traverse ) 對其進行 ( 深度優(yōu)先遍歷 )
      • 在此遍歷過程中對節(jié)點進行 ( 添加 )祸轮、( 更新 ) 及 ( 移除 ) 操作
      • traverse:是遍歷的意思
    • <font color=red>@babel/types</font>:主要用來操作AST兽埃,比如 ( 添加 )、( 更新 ) 及 ( 移除 ) 操作
      • 除了手動替換适袜,可以使用@babel/types更加房便快捷
      • 相當(dāng)于作用于 AST 的類 lodash 庫
    • @babel/traverse
    • @babel/types
  • 生成 generate
    • <font color=red>@babel/generator</font>:來將轉(zhuǎn)換后的抽象語法樹轉(zhuǎn)化為Javascript 字符串
      • 將經(jīng)過轉(zhuǎn)換的AST通過babel-generator再轉(zhuǎn)換為js代碼
      • 過程及時深度遍歷整個AST,然后構(gòu)建轉(zhuǎn)換后的代碼字符串柄错。
    • @babel/generator
image
image

@babel/parser

babelParser.parse(code, [options]) ------------------------------------ 解析所有代碼
babelParser.parseExpression(code, [options]) -------------------------- 解析單個表達式

參數(shù):
- code:表示源碼字符串
- options:配置對象,可選
    - allowImportExportEverywhere:默認import和export聲明只能出現(xiàn)在頂部,當(dāng)此選項為true則可以出現(xiàn)在任何地方
    - ...

@babel/traverse

  • 因為 ( @babel/parser解析 ) 和 ( @babel/generator生成 ) 基本不會變化售貌,所以重點是 ( @babel/traverse轉(zhuǎn)換 )
import * as babylon from "babylon";
import traverse from "babel-traverse";

// 源碼string
const code = `function square(n) {
  return n * n;
}`;

// 解析 parse:string -> ast
const ast = babylon.parse(code);

// 轉(zhuǎn)換 transform:ast -> modified ast
traverse(ast, {
  enter(path) {
    if (
      path.node.type === "Identifier" &&
      path.node.name === "n"
    ) {
      path.node.name = "x"; // ---------------- 如果是標(biāo)識符并且標(biāo)識符的名字是n冕房,就把n改為x
    }
  }

@babel/generator

import {parse} from '@babel/parser';
import generate from '@babel/generator';

const code = 'class Example {}';
const ast = parse(code);

const output = generate(ast, { /* options */ }, code);

babel轉(zhuǎn)化代碼案例

  • 需求:將小寫變量轉(zhuǎn)換成大寫
// 輸入
const numberFive = 5;

// 輸出
const NUMBERFIVE = 5;
  • 實現(xiàn)過程
安裝 

@babel/core ----------------------- babel核心模塊
@babel/parser --------------------- 字符流 -> token流 -> AST
@babel/traverse ------------------- AST -> modified AST
@babel/generator ------------------ modified AST -> 字符流

npm install @babel/core @babel/parser @babel/traverse @babel/generator -S
代碼

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;

// 源碼字符串
const code = `
  const nubmerFive = 5
`;

// 解析
let AST = parser.parse(code)

// 轉(zhuǎn)換
traverse(AST, {
  enter(path) {
    console.log(path.node.type, 'path.node.type')
    if (path.node.type === 'Identifier') { // 如果node類型是標(biāo)識符,就將name轉(zhuǎn)成大寫形式
      path.node.name = path.node.name.toUpperCase()
    }
  }
})

// 生成
const outputObj = generator(AST)
const outputStr = outputObj.code;

console.log(outputStr, 'outputStr')

資料

AST babel-AST相關(guān)工具 https://juejin.im/post/6844903992762318855
AST 從babel講到AST https://juejin.im/post/6844903581582098446
AST 99%的人不了解的AST https://segmentfault.com/a/1190000016231512
AST 抽象語法樹-圖形 https://juejin.im/post/6844903727451602951
AST 具體細節(jié):https://segmentfault.com/a/1190000016231512
AST https://cheogo.github.io/learn-javascript/201709/runtime.html
AST詳細 https://www.codercto.com/a/88752.html

babel轉(zhuǎn)換 https://juejin.im/post/6844903992762318855
babel轉(zhuǎn)換案例 https://cloud.tencent.com/developer/article/1444654
babel插件介紹 https://zhuanlan.zhihu.com/p/61780633

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趁矾,一起剝皮案震驚了整個濱河市耙册,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌毫捣,老刑警劉巖详拙,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔓同,居然都是意外死亡饶辙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門斑粱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弃揽,“玉大人,你說我怎么就攤上這事则北】笪ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵尚揣,是天一觀的道長涌矢。 經(jīng)常有香客問我,道長快骗,這世上最難降的妖魔是什么娜庇? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮方篮,結(jié)果婚禮上名秀,老公的妹妹穿的比我還像新娘。我一直安慰自己藕溅,他們只是感情好匕得,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜈垮,像睡著了一般耗跛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攒发,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天调塌,我揣著相機與錄音,去河邊找鬼惠猿。 笑死羔砾,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姜凄,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼政溃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了态秧?” 一聲冷哼從身側(cè)響起董虱,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎申鱼,沒想到半個月后愤诱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡捐友,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年淫半,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匣砖。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡科吭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出猴鲫,到底是詐尸還是另有隱情对人,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布变隔,位于F島的核電站规伐,受9級特大地震影響蟹倾,放射性物質(zhì)發(fā)生泄漏匣缘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一鲜棠、第九天 我趴在偏房一處隱蔽的房頂上張望肌厨。 院中可真熱鬧,春花似錦豁陆、人聲如沸柑爸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽表鳍。三九已至,卻和暖如春祥诽,著一層夾襖步出監(jiān)牢的瞬間譬圣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工雄坪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厘熟,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像绳姨,于是被迫代替她去往敵國和親登澜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容