导航
[[深刻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()会尝试在思考性能的状况下解析单个Expressiondoubt:纳闷// 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";// 源码stringconst code = `function square(n) {return n * n;}`;// 解析 parse:string -> astconst ast = babylon.parse(code);// 转换 transform:ast -> modified asttraverse(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/...