30分钟学会JS AST,打造自己的编译器

这是一棵树嘛
直奔主题
抽象语法树是js代码另一种结构映射,可以将js拆解成AST,也可以把AST转成源代码。这中间的过程就是我们的用武之地。 利用 抽象语法树(AST) 可以对你的源代码进行修改、优化,甚至可以打造自己的编译工具。其实有点类似babel的功能。
AST高深的狠吓人?
AST很简单,并没有你想象的那样高深。很多地方都把这个技术给夸大了,什么编译原理,抽象语法树 光看这名字就觉得吓人。当然一项技术总归要起个名字,就像给自己的孩子取名字,肯定要起一个高大上,深有寓意的名字。所以,名字只是一个代号。从名字来看就会让很多人望而却步。但是ast超级简单,但是功能超级强大。
我们能用这个技术做很多有意思的东西,只要你能想到的。
本文术道结合,让你感受到ast的有趣和简单,从此爱上ast,还能根据自己的需要打造自己的编译器。
什么是AST?
ast全称是abstract syntax tree,翻译过来叫-抽象语法树。其实这含两个意思,一个是“抽象”,一个是“树”。抽象表示把js代码进行了结构化的转化,转化为一种数据结构。这种数据结构其实就是一个大的json对象,json我们都熟悉,他就像一颗枝繁叶茂的树。
有树根,有树干,有树枝,有树叶.无论多小多大,都是一棵完整的树。
如何生成AST?
你可以大致的想一下如果亲自实现把js代码转换成结构化的数据我们应该怎么做?
有点像小时候拆解自己的玩具,每个零件之间都有着从属关系。
对于如何生成ast,我们可能会想到分析js代码的规则使用字符串处理、正则匹配等方法,如果对简单的代码处理我们是可以实现的。但是如果能够对随意的一段代码进行处理那就需要考虑非常多的情况。具体如何实现咱们不必过于纠结,这也不是重点。
但最终的实现里我们能想到方法基本都会被用到。我们可以简化理解,也就是对js代码经过了一系列的加工处理,变成了一堆零件或者食材(像老妈给我们做的香喷喷的饭菜,但前提是先准备好菜)。
这个拆解的过程可能较为复杂,所以我们需要用现成方法,直接拿过来用就可以了。
所以我们需要用到esprima、UglifyJS等库,做菜的食材有很多种,所以会存在很多这样的三方库,而我们会使用其中一种就可以了。
先使用esprima 种菜,体会一下
种子:

成熟:

有了AST能做什么?
到这一步你已经可以把js代码转换成一棵结构化的树了,那下一步要做什么呢? 比如在没有树的情况下,你要对代码里的某个代码进行替换。要把所有 console.log给注释掉或者删除,你可能会使用IDE的查找替换或者用node写一个方法,读取文件然后查找替换。
这种方式不够安全也不够科学,稍有不慎就会把代码给搞坏了。
但这个时候你有了结构化代码树,是不是只要对这棵树进行修修剪剪然后把这棵树转换成为js代码就可以了呢?
答案:肯定是可以的。因为树已经发生了变化,修改了树就相当于修改了源码。
怎样操作这棵树呢?我想你应该已经知道了,就是对这json对象进行操作,方法就多了去了,前提是你得有一点点js基础。
又一个问题,怎样把树再转成代码?
脑洞打开,用递归加字符串拼接,这个方法应该是可以的。
但是这棵树不是你生成的,结构特点你并不清楚,成千上万个节点呢?怎么拼接?真要干,那可能得搞得流鼻血。
这就像是食材准备好了,转换成源码的过程就是炒菜的过程。具体的转源码的原理不多说,也不必纠结。使用现成的方法就可以,所以要用到estraverse,escodegen这两个库。
estraverse 可以遍历树的所有节点,省去你对树的递归遍历
escodegen 可以把树再加工转成源代码
过程总结
到这里始终都没有提到任何代码,只是理论了一番,但是相信你已经理解了ast以及ast的作用。然后在述说过程中引出了3个库,有了这三个库就可以对你的js代码进行多样化处理,只要你能想到的。
看图理解整个处理过程:

这个过程简单,清晰,所以说ast简单、有趣、好玩。因为此刻代码可以被你任意的蹂躏了。
实例应用
说的再清楚都不够直观,毕竟都是脑补,不如看代码来的爽快。
这里就拿日常编码中的一些小问题举例,来演示一下AST的使用。
1. 把 == 改为全等 ===
2. 把parsetInt不标准的调用改为标准用法 parseInt(a)-> parseInt(a,10)
这里我使用esprima的官方工具生成了ast,工具地址http://esprima.org/demo/parse.html
看下要处理的源码:

转成ast,由于转成树后结构非常大,所以这里我只贴了一部分,你也可以到工具页面自己生成下。


ast看上去结构复杂,盯着仔细看后基本都能看懂。所有的代码都在特定的节点里面。具体的这里就不介绍了,可以到上面的工具地址去观察不同的ast结构。总之这就是一个对象,只要你能对这个对象进行修改、添加、删除即可。
开始实现以上功能
init

2.把 == 改为全等 ===

3. 把parseInt改成标准调用

代码不多,需求简单,但已足够能说明整个处理过程以及ast的强大。 ast的节点很多,有些凌乱,送你一首歌【汪峰的无所谓】,操作的时候只要关心你自己的需求就可以,不需要对所有的节点都搞明白。按需处理就可以。
AST技术的应用
虽然平时用不到ast,但又时刻都在使用ast技术。家喻户晓、无人不知的babel,webpack,还有jd taro等都把ast用的淋漓尽致,脱离了ast他们就跪了。
AST这么简单,好没技术含量
AST没有技术含量吗?怎么可能呢,如果真这么认为怕是会被笑掉大牙的。如果仅仅停留在使用层面的话,理解到这步已经基本可以了,只要是你能对这棵树做修剪就可以对源代码做手脚。
另外ast怎样生成的?怎样把ast转换成源码的?这就有点高深了。会使用就像是在山脚下能看到的风景有限,理解了背后原理机制就像是爬上了山顶,别样的风景尽收眼底。不过上不上山看个人兴趣,有兴趣的同学可以去看源码、做研究,这里就不再多说,因为我也不知道。哈哈哈
总结
本文主要介绍了
什么是ast:
ast其实就把js代码进行抽象为一种json结构;
ast的用途:
利用ast可以方便的优化和修改代码,还能打造自己的编译器;
然后通过具体的示例演示了怎样操作ast,最终是希望你能对ast有一个系统全局的认识和理解并能够利用ast打造自己的编译工具。
演示代码下载,欢迎star
https://github.com/bigerfe/zdqd-demos
自家观点,欢迎打脸
原创不易,请多鼓励

30分钟学会JS AST,打造自己的编译器的更多相关文章
- 【grunt第二弹】30分钟学会使用grunt打包前端代码(02)
前言 上一篇博客,我们简单的介绍了grunt的使用,一些基础点没能覆盖,我们今天有必要看看一些基础知识 [grunt第一弹]30分钟学会使用grunt打包前端代码 配置任务/grunt.initCon ...
- 30分钟学会使用Spring Web Services基础开发
时隔一年终于又推出了一篇30分钟系列,上一篇<30分钟学会反向Ajax>是2016年7月的事情了.时光荏苒,岁月穿梭.虽然一直还在从事Java方面的开发工作,但是私下其实更喜欢使用C++. ...
- 30 分钟学会 Flex 布局
30 分钟学会 Flex 布局 有酒 617 人赞同了该文章 为什么我要写这一篇关于 Flex 布局的教程? 因为它十分简单灵活,区区简单几行代码就可以实现各种页面的的布局,以前我在学习页面布局的 ...
- 30分钟学会XAML
1.狂妄的WPF 相对传统的Windows图形编程,需要做很多复杂的工作,引用许多不同的API.例如:WinForm(带控件表单).GDI+(2D图形).DirectX API(3D图形)以及流媒体和 ...
- 30分钟学会如何使用Shiro
本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jinnianshilongnian.iteye.com/blog/2018936 我并没有全部看完,只是选择了一部分 ...
- 教你30分钟学会XAML
1.狂妄的WPF 相对传统的Windows图形编程,需要做很多复杂的工作,引用许多不同的API.例如:WinForm(带控件表单).GDI+(2D图形).DirectX API(3D图形)以及流媒体和 ...
- 30分钟学会Objective-C
注: 本文首发于我的个人博客:https://evilpan.com/2019/04/05/objc-basics/ 请原谅我的标题党.但是如果你有其他语言的学习经验,要学习Objective-C的语 ...
- 30分钟学会Docker里面开启k8s(Kubernetes)登录仪表盘(图文讲解)
前言 我们之前搭建了第一个docker项目: windows环境30分钟从0开始快速搭建第一个docker项目(带数据库交互):https://www.cnblogs.com/xiongze520/p ...
- 【grunt整合版】30分钟学会使用grunt打包前端代码
grunt 是一套前端自动化工具,一个基于nodeJs的命令行工具,一般用于:① 压缩文件② 合并文件③ 简单语法检查 对于其他用法,我还不太清楚,我们这里简单介绍下grunt的压缩.合并文件,初学, ...
随机推荐
- 2019.04.17 读书笔记 checked与unchecked
在普通的编程中,我们是很容易去分析数据的大小,然后给出合理的类型,但是在很多数据库的累计中,缺存在很多隐患,特别是研发时,数据量小,求和也不会溢出,当程序运行几年后,再来一次大求和,隐形的BUG就出来 ...
- 《大数据日知录》读书笔记-ch2数据复制与一致性
CAP理论:Consistency,Availability,Partition tolerance 对于一个分布式数据系统,CAP三要素不可兼得,至多实现其二.要么AP,要么CP,不存在CAP.分布 ...
- 浏览器获取WEB服务器时间
/* * 获取XMLHttpRequest对象 */ function CreateXMLHttpRequest() { var xmlreq = false; if (window.ActiveXO ...
- Ubuntu系统下安装并配置hive-2.1.0
说在前面的话 默认情况下,Hive元数据保存在内嵌的Derby数据库中,只能允许一个会话连接,只适合简单的测试.实际生产环境中不使用,为了支持多用户会话, 则需要一个独立的元数据库,使用MySQL作为 ...
- execution(* *..BookManager.save(..))的解读
execution(* *..BookManager.save(..))的解读: 第一颗* 代表ret-type-pattern 返回值可任意, *..BookManager 代表任意Pacakge里 ...
- Spark中自定义累加器Accumulator
1. 自定义累加器 自定义累加器需要继承AccumulatorParam,实现addInPlace和zero方法. 例1:实现Long类型的累加器 object LongAccumulatorPara ...
- 开发常用的 JavaScript 知识点总结
No1.语法和类型 1.声明定义 变量类型:var,定义变量:let,定义块域(scope)本地变量:const,定义只读常量.变量格式:以字母.下划线“_”或者$符号开头,大小写敏感.变量赋值:声明 ...
- 连锁咖啡厅B/S架构点餐系统开发
需求号:5255128 http://task.zhubajie.com/5255128/ 具体要求: 网站用途:连锁咖啡厅B/S架构点餐系统开发开发周期:1.5个月功能要求: 支持触摸屏点菜.无线P ...
- Java如何实现form表单提交的数据自动对应实体类(源码)
原文出自:https://blog.csdn.net/seesun2012 原生Java+JQuery form表单serializeArray提交自动对应java实体,这是一个实际的例子: html ...
- window.history,页面中的返回按钮
一.页面中的返回按钮事件 window.history可以不加window这个前缀 他的方法有: window.history.go(-1); //-n表示后退n页,n表示前进n页,或者是一个url ...