共计 8664 个字符,预计需要花费 22 分钟才能阅读完成。
导航
[[深刻 01] 执行上下文 ](https://juejin.im/post/684490…
[[深刻 02] 原型链 ](https://juejin.im/post/684490…
[[深刻 03] 继承 ](https://juejin.im/post/684490…
[[深刻 04] 事件循环 ](https://juejin.im/post/684490…
[[深刻 05] 柯里化 偏函数 函数记忆 ](https://juejin.im/post/684490…
[[深刻 06] 隐式转换 和 运算符 ](https://juejin.im/post/684490…
[[深刻 07] 浏览器缓存机制(http 缓存机制)](https://juejin.im/post/684490…
[[深刻 08] 前端平安 ](https://juejin.im/post/684490…
[[深刻 09] 深浅拷贝 ](https://juejin.im/post/684490…
[[深刻 10] Debounce Throttle](https://juejin.im/post/684490…
[[深刻 11] 前端路由 ](https://juejin.im/post/684490…
[[深刻 12] 前端模块化 ](https://juejin.im/post/684490…
[[深刻 13] 观察者模式 公布订阅模式 双向数据绑定 ](https://juejin.im/post/684490…
[[深刻 14] canvas](https://juejin.im/post/684490…
[[深刻 15] webSocket](https://juejin.im/post/684490…
[[深刻 16] webpack](https://juejin.im/post/684490…
[[深刻 17] http 和 https](https://juejin.im/post/684490…
[[深刻 18] CSS-interview](https://juejin.im/post/684490…
[[深刻 19] 手写 Promise](https://juejin.im/post/684490…
[[深刻 20] 手写函数 ](https://juejin.im/post/684490…
[[react] Hooks](https://juejin.im/post/684490…
[[部署 01] Nginx](https://juejin.im/post/684490…
[[部署 02] Docker 部署 vue 我的项目 ](https://juejin.im/post/684490…
[[部署 03] gitlab-CI](https://juejin.im/post/684490…
[[源码 -webpack01- 前置常识] AST 形象语法树 ](https://juejin.im/post/684490…
[[源码 -webpack02- 前置常识] Tapable](https://juejin.im/post/684490…
[[源码 -webpack03] 手写 webpack – compiler 简略编译流程 ](https://juejin.im/post/684490…
[[源码] Redux React-Redux01](https://juejin.im/post/684490…
[[源码] axios ](https://juejin.im/post/684490…
[[源码] vuex ](https://juejin.im/post/684490…
[[源码 -vue01] data 响应式 和 初始化渲染 ](https://juejin.im/post/684490…
[[源码 -vue02] computed 响应式 – 初始化,拜访,更新过程 ](https://juejin.im/post/684490…
[[源码 -vue03] watch 侦听属性 – 初始化和更新 ](https://juejin.im/post/684490…
[[源码 -vue04] Vue.set 和 vm.$set ](https://juejin.im/post/684490…
[[源码 -vue05] Vue.extend ](https://juejin.im/post/684490…
[[源码 -vue06] Vue.nextTick 和 vm.$nextTick ](https://juejin.im/post/684790…
前置常识
一些单词
abstract:形象的
(abstract syntax tree:形象语法树)
Identifier:标识符
Punctuator:标点符号
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:数字
一些网站
AST explorer 查看源码对应的 AST 和 JSON 构造
esprima 能够查看词法分词阶段生成的 tokens
AST 可视化工具 查看 AST 可视化树状图
AST 对象文档
从 javascript 程序到机器可执行的机器码须要经验三个阶段
- 语法查看:词法剖析,语法分析
- 编译运行
- 总结:词法剖析 -> 语法分析 -> 编译运行
AST
abstract syntax tree:形象语法树
abstract:形象的
AST 利用场景
- 代码 (语法检测),代码 (格调检测),代码 (格式化),代码 (高亮),代码 (谬误提醒),代码 (主动补全)
- eslint amd cmd
- <font color=red> webpack 通过 babel 本义 js 语法 </font>
AST 解析过程
- (1) 读取 js 文件中的 (<font color=red> 字符流 </font>)
- (2) 通过 (<font color=red> 词法剖析 </font>) 生成 token ———– 词法剖析也叫扫描 scanner,分词阶段,token 是一维数组
- (3) 通过 (<font color=red> 语法分析 </font>) 生成 AST ————- 语法分析也叫解析器
- (4) 生成 (<font color=red> 机器码 </font>) 执行 ——————– 编译阶段也叫编译器
词法剖析
- 词法剖析是将 (<font color=red> 字符流 char stream</font>) 转换为 (<font color=red> 记号流 token stream</font>)
- <font color=red>token 是不可分割的最小单元,是一个一维数组 </font>
- (词法剖析) 也称之为 (扫描 scanner)
- (<font color=red> 词法分析器 </font>) 里的每一个 (<font color=red> 关键字,标识符,操作符,标点符号,字符串,数字,布尔值,正文符,空白字符,空格,换行符 </font>) 等都是一个 token
- <font color=blue>token 数组中,每一个对象蕴含 (type) 和 (value)</font>
- type
-
value
- 常见的 (type) 如下:
- <font color=blue>Keyword(关键词)</font>
- <font color=blue>Identifier(标识符)</font>
- <font color=blue>Punctuator(标点符号)</font>
- <font color=blue>Numeric(数字)</font>
- <font color=blue>String(字符串)</font>
- <font color=blue>Boolean(布尔)</font>
- <font color=blue>Null(空值)</font>
-
最终代码被宰割进一个 tokens 列表,即一维数组
源码 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 属性的对象组成的数组 (2) token 是词法剖析的最小单元,不能再合成
- keyword 关键字
- identfier 标识符
- punctuator 标点符号
-
Numeric:数字
语法分析
- (<font color=red> 语法分析 </font>) 会将词法剖析得出的 token 转化成 (<font color=red> 有语法含意 </font>) 的 (<font color=red> 形象语法树 </font>) 构造
- 同时 (<font color=red> 验证语法 </font>),有语法错误则抛出语法错误
-
属性
-
最外层蕴含:
- (<font color=red>type</font>)
- (<font color=red>sourceType</font>)
- (start)
- (end) 等
-
(<font color=red>body</font> )
-
body:是一个 (数组),蕴含多个 (<font color=red> 内容块对象 statement </font> ),每个内容块蕴含
- type
- start
- end
- kind
-
<font color=red>declarations</font>:乘装变量内容的块,这个块也是一个数组,因为变量申明可能申明多个
- type
- start
- end
-
<font color=red>id</font>
- type
- start
- end
- <font color=red>name</font>
-
-
-
(statement – body 数组中的对象 ) 有很多类型,比如说变量申明,函数定义,if 语句,while 循环,等都是一个 statement
- VariableDeclaration:变量申明
- FunctionDeclaration:函数定义
- IfStatement:if 语句
- WhileStatement:while 循环
源码:var a = 1; AST { "type": "Program", "start": 0, "end": 12, "body": [ // ---------------------------------------------- body 示意代码具体的内容 { // ---------------------------------------------------- statement 内容块对象,一个 body 可能蕴含多个 statement "type": "VariableDeclaration", // --------------------- 变量申明 "start": 0, "end": 10, "declarations": [ { "type": "VariableDeclarator", // ------------------ 变量申明 "start": 4, "end": 9, "id": { "type": "Identifier", // ------------------------- 标识符 "start": 4, "end": 5, "name": "a" }, "init": { "type": "Literal", "start": 8, "end": 9, "value": 1, "raw": "1" } } ], "kind": "var" // --------------------------------------- 变量类型 } ], "sourceType": "module" } 阐明:
-
body:示意代码的具体内容
- 内容块:body 中可能蕴含多个内容块,每个内容块用一个对象示意
-
内容块蕴含:
- type
- start
- end
- kind
-
declarations:乘装变量内容的块,这个块也是一个数组,因为变量申明可能生命多个
- type
- start
- end
-
id
- type
- start
- end
- name
-
sourceType:示意语言的品种
(2) body 是一个数组,成员是 statement 内容块对象,因为 body 能够蕴含多个 statement 内容块
-
statement 有很多类型,比如说变量申明,函数定义,if 语句,while 循环,等都是一个 statement
- VariableDeclaration:变量申明
- FunctionDeclaration:函数定义
- IfStatement:if 语句
- WhileStatement:while 循环
Babel 原理
- babel 编译的过程:<font color=red> 解析 parse -> 转换 transform -> 生成 generate</font>
-
解析 parse
- <font color=red>@babel/parser</font>:将字符串转换成 AST,Babylon(当初是 @babel/parser) 是 Babel 中应用的 JavaScript 解析器
-
解析过程分为两个阶段
- 语法分析:字符流 -> token 流
- 词法剖析:token 流 -> AST
- @babel/parser
-
转换 transform
-
<font color=red>@babel/traverse</font>:次要用于遍历 AST
- Babel 接管解析失去的 AST 并通过 (babel-traverse) 对其进行 (深度优先遍历)
- 在此遍历过程中对节点进行 (增加)、(更新) 及 (移除) 操作
- traverse:是遍历的意思
-
<font color=red>@babel/types</font>:次要用来操作 AST,比方 (增加)、(更新) 及 (移除) 操作
- 除了手动替换,能够应用 @babel/types 更加房便快捷
- 相当于作用于 AST 的类 lodash 库
- @babel/traverse
- @babel/types
-
-
生成 generate
-
<font color=red>@babel/generator</font>:来将转换后的形象语法树转化为 Javascript 字符串
- 将通过转换的 AST 通过 babel-generator 再转换为 js 代码
- 过程及时深度遍历整个 AST, 而后构建转换后的代码字符串。
- @babel/generator
-
@babel/parser
babelParser.parse(code, [options]) ------------------------------------ 解析所有代码
babelParser.parseExpression(code, [options]) -------------------------- 解析单个表达式
参数:- code:示意源码字符串
- options:配置对象,可选
- allowImportExportEverywhere:默认 import 和 export 申明只能呈现在顶部,当此选项为 true 则能够呈现在任何中央
- ...
@babel/traverse
-
因为 (@babel/parser 解析) 和 (@babel/generator 生成) 根本不会变动,所以重点是 (@babel/traverse 转换)
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); // 转换 transform:ast -> modified ast traverse(ast, {enter(path) { if ( path.node.type === "Identifier" && path.node.name === "n" ) {path.node.name = "x"; // ---------------- 如果是标识符并且标识符的名字是 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 转化代码案例
-
需要:将小写变量转换成大写
// 输出 const numberFive = 5; // 输入 const NUMBERFIVE = 5;
-
实现过程
装置 @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)
// 转换
traverse(AST, {enter(path) {console.log(path.node.type, 'path.node.type')
if (path.node.type === 'Identifier') { // 如果 node 类型是标识符,就将 name 转成大写模式
path.node.name = path.node.name.toUpperCase()}
}
})
// 生成
const outputObj = generator(AST)
const outputStr = outputObj.code;
console.log(outputStr, 'outputStr')
材料
AST babel-AST 相干工具 https://juejin.im/post/684490…
AST 从 babel 讲到 AST https://juejin.im/post/684490…
AST 99% 的人不理解的 AST https://segmentfault.com/a/11…
AST 形象语法树 - 图形 https://juejin.im/post/684490…
AST 具体细节:https://segmentfault.com/a/11…
AST https://cheogo.github.io/lear…
AST 具体 https://www.codercto.com/a/88…
babel 转换 https://juejin.im/post/684490…
babel 转换案例 https://cloud.tencent.com/dev…
babel 插件介绍 https://zhuanlan.zhihu.com/p/…