作者:尚建尧来源:恒生LIGHT云社区Babel作为现代前端项目的必备技术,是一个将最前沿的JS语法转换为浏览器支持的语法的编译器。接下来,让我们一起深入研究。巴别塔的介绍巴别塔指的是“巴别塔”,来源于圣经故事:当时的人类只会说一种语言,联合起来建造通向天堂的塔时便无所不能。上帝害怕,为了将他们分开,所以就让人类说不同的语言,人类就失去了这种力量,变得有区别了。而这座塔就是巴别塔。Babel的目的是将esnext、typescript、flow等翻译成目标环境支持的js。这是最常用的功能。用于将代码中esnext、ts、flow的语法转换为基于目标环境支持的语法实现。并且您可以polyfill目标环境不支持的API。免费编译器公开了很多API。您可以随意翻译源代码。代码的静态分析。代码解析后可以转换,因为AST结构可以理解代码并生成转换前的目标代码,也可以用来分析代码的信息并进行校验。比如linter,一个api文档自动生成工具,通过提取注释生成文档等。Babel的翻译过程Babel是源到源的转换。整体翻译过程分为三个步骤:解析:通过解析器将源代码转化为抽象语法树(AST)变换:遍历AST,调用各种变换插件对AST进行增删改查generate:将转换后的AST打印成目标代码,并生成sourcemap。为什么是三步而不是一步?因为源码太乱,没有统一的格式,直接源码到源码不现实,所以加了一层AST,去掉源码中混乱无意义的部分,使得对AST的操作可以统一。所以一步变成三步。(经典中间件思维)简单分析一下parse的三个步骤。之前说过parse是将源码转成统一格式的AST。这个过程是词法分析和语法分析的过程;比如letname='shangjianyao';对于一段代码,parse先把它分成不能再细分的词(这个词叫做token)得到let,name,=,'shangjianyao'。这个过程称为词法分析,根据单词的组成规则对源代码进行拆分。之后,令牌必须递归组装以产生AST。这个过程就是语法分析,将一组词按照不同的语法规则组合成对象。也就是先把它拆开,再按照新的规则组装起来。transformtransform阶段对parse生成的AST进行处理:对AST进行深度优先遍历,遍历过程中处理不同的AST节点,调用注册的对应vistor函数(插件派生)。vistor函数可以添加、删除和修改AST节点,返回新节点。这一步是逻辑处理的核心,也是变化的关键。generate这个阶段会将AST打印为目标字符串并生成sourcemap。不同的AST对应不同结构的字符串。sourcemap记录了源代码到目标代码的转换关系,通过它可以找到目标代码中每个节点对应的源代码位置。再来说说ASTAST(AbstractSyntaxTree)抽象语法树,它是整个翻译过程的核心。它是一个树状结构,有不同类型的节点,基本对应JS语法中的数据类型和语法。分别理解一下:LiteralLiteral字面量,比如letname='shangjianyao',shangjianyao是一个字符串字面量StringLiteral,对应的还有数值字面量NumericLiteral,布尔字面量BooleanLiteral,空字面量NullLiteral,未定义字面量UndefinedLiteral,这些都是字面量,规则是像这样——xxLiteral。Identifier也是标识符的意思。变量名、属性名、参数名等各种声明和引用的名称都是Ientifers。(js中的标识符规则是什么?Identifer就是识别规则)试试看,下面的代码有多少个标识符?letname='shangjianyao';functionsayHello(name){console.log('hello'+name);}图中红色下划线都是标识符:Statementstatement是语句,是一个可以独立执行的单元,例如,它包含一些保留字或关键字,如break、continue、return或流控制if、for、while等,以及声明语句和表达式语句,都是语句。一般来说,我们写的每一段可以独立执行的代码都是一条语句。下面是一些常用的语句,每一行是一条语句:break;continue;return;debugger;throwError();{}try{}catch(e){}finally{}for(;;){}while(true){}do{}while(true);switch(x){case1:break;default:;}console.log();with(x){}stament名称组合也类似字面规则,都是xxStatement,比如break对应BreakStament。声明语句是一种特殊的语句,它执行的逻辑是在作用域内声明一个变量、函数、类、导入、导出等。例如:constname='shangjianyao';functionsayHello(name){}classPerson{}import{name}from'./name';export{name};exportdefaultname;export*from'./name';对应的DeclarationStatement,例如:Expressionexpression是一个表达式,其特点是执行后有返回值,这与语句不同。常用的表达式有:[1,2,3];name='shangjianyao';1+1;-1;function(){}()=>{}class{}name;this;super;a::b;对应的表达式为xxExpression,例如:对于上面的表达式,标识符是怎么混进去的呢?由于标识符返回一个值,因此它也是一个表达式。有些表达式不能单独执行,如匿名函数表达式、匿名类表达式,需要和其他部分组成一条语句。当一个表达式被解析时,它会被一层ExpressionStatement包裹起来,表示该表达式是作为一个语句来执行的。Class是一个重要的语法糖,class还有一个特殊的AST节点标识。整个类的内容是ClassBody,属性是ClassProperty,方法是MethodDefinition。通过MethodDefinition字段区分构造函数和普通方法。例如,下面的代码:classPerson{constructor(name){this.name=name;}sayHello(){console.log('你好'+this.name);}}对应的ASTModuleses模块是语法级的模块规范,所以也有专门的AST节点。//nameimportimport{name}from'./name';//defaultimportimportnamefrom'./name';//namespaceimportimport*asnamefrom'./name';对应的AST有不同的语法在importDeclaration节点中,通过specifiers字段来区分import的类型,分别对应importSpecifier、importDefaultSpecifier、importNamespaceSpecifier。//nameexportexport{name};//defaultexportexportdefaultname;//allexportexport*from'./name';对应的AST分别对应ExportNameDeclaration、ExportDefaultDeclaration、ExportAllDeclaration。只有ExportNameDeclaration有说明符字段。Program&Directiveprogram是一个节点,代表了整个程序。它有一个body字段,是一个数组,存储了所有的语句和执行语句的集合。directives属性存放Directive节点,比如usestrict。Program是一个节点,包裹着具体的执行语句,而Directive是代码中的一条指令。File&CommentBabel的AST的最外层节点是File,具有program、comments、tokens等属性,分别存储程序体、comments、tokens等,是最外层节点。注释分为块注释(/**/)和行注释(//)。公共属性每个节点都有自己的属性来标识其身份。自然地,构建和维护AST也需要一些公共属性,比如:type:AST节点类型start,end,loc:start和end表示对应的节点源码字符串的开始和结束下标不区分等级和专栏。loc是一个对象,具有line和column属性,分别记录开始和结束的行号和列号。leadingComments、innerComments、trailingComments:leadingComments、innerComments、trailingComments分别存储前一条评论、中间评论、尾随评论。extra:存放一些额外的信息,比如StringLiteral修改value只是对value的修改,而修改extra.raw可以单引号和双引号一起修改。AST可视化查看工具以上这些我们不需要记住太多,需要的时候在可视化AST中查看即可。或者从Babel解析器存储库中查看AST。或者查看@Babel/types的打字稿类型定义摘要。本文简单介绍一下Babel的用途:将look-aheadsyntax翻译成compatiblesyntax。介绍了Babel的翻译过程:sourcecode->AST->transformedAST->code+sourcemap介绍了AST是如何抽象sourcecode的:使用各种节点来描述sourcecode。比如标识符Identifier、表达式xxExpression、语句xxStatement、声明语句xxDeclaration、字面量xxLiteral、类、模块、文件、Program、Directicve、Comment等。知道了有哪些节点,你就知道如何用AST来识别源代码。当然,你不需要记住它。使用(astexpoler.net)进行目测比较理想。下一节我们将学习Babel的api,并进行简单的实战。下次见。??想向技术领导者学习很多东西吗?开发中遇到的问题在哪里讨论?如何获取海量金融科技资源?恒生LIGHT云社区,恒生电子打造的金融科技专业社区平台,分享实用技术干货、资源数据、金融科技行业动态,拥抱所有金融开发者。扫描下方小程序二维码加入我们吧!
