導(dǎo)航
[封裝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>
- body:是一個 ( 數(shù)組 ) 庶弃,包含多個 ( <font color=red>內(nèi)容塊對象 statement </font> ),每個內(nèi)容塊包含
- 最外層包含:
- ( 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)
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
- <font color=red>@babel/traverse</font>:主要用于遍歷AST
-
生成 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
- <font color=red>@babel/generator</font>:來將轉(zhuǎn)換后的抽象語法樹轉(zhuǎn)化為Javascript 字符串
@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