当前位置: 首页 > 科技观察

说说Babel背后执行的是什么?

时间:2023-03-22 00:56:34 科技观察

babel背后到底执行了什么?Babel对于大多数前端开发者来说并不陌生,但它背后的原理却是一个黑盒子。我们需要了解babel背后的原理在我们的开发中被广泛使用。1、babel[1,2,3].map(n=>n+1);的简单应用babel翻译后代码变成这样[1,2,3].map(function(n){returnn+1;})那么我们应该知道babel的定位:babel将ES6新引入的语法转换成ES5浏览器可以运行的语法。2、babel背后的babel流程:解析-转换-生成。在babel背后的过程中,我们看到了一个叫做AST(抽象语法树)的东西。主要有三个过程:解析:将代码(字符串)转换为AST(抽象语法树)。Transformation:访问AST的节点进行变更操作,生成新的AST。生成:基于新的ASTIII生成代码。过程一:代码解析(parse)代码解析(parse)将一段代码解析成一个数据结构。主要的关键步骤是:词法分析:代码(字符串)被划分为token流。即,语法单元数组。语法分析:分析token流(生成的数组)生成AST。3.1词法分析词法分析,首先要了解JS中有哪些语法单元?数字:科学计数法和js中的普通数组都是语法单位。括号:只要有(and)出现,不管意义如何,都认为是语法单位。标识符:连续字符、公共变量、常量、关键字等。运算符:+、-、*、/等。注释和括号。下面看一个简单的词法分析器(Tokenizer)//词法分析器接收字符串并返回token数组0;while(current/.test(char)){letvalue='';value+=char;current++;while(/=|\+|>/.test(code[current])){value+=code[current];current++;}//当=后面是>时,是箭头函数而不是运算符if(value==='=>'){tokens.push({type:'ArrowFunctionExpression',value,});continue;}tokens.push({type:'operator',value,});continue;}//如果遇到词法分析如果没有指定字符,thrownewTypeError('Idontknowwhatthischaracteris:'+char);}returntokens;};上述词法分析器:主要针对示例的箭头函数3.2句法分析这种可能性需要开发者根据token流(我们上一节生成的token数组)提供的信息来分析代码之间的逻辑关系。只有经过词法分析,令牌流才能成为结构化的抽象语法树。最好按照语法分析的标准。大多数JavaScript解析器都遵循estree规范1.语句:语句是JavaScript中非常常见的语法。我们常见的循环,if判断,异常处理语句,with语句等都属于statement。2.表达式:表达式是一组有返回值的代码。表达式是另一种非常常见的语法。函数表达式是一个典型的表达式。如果你不明白什么是表达式MDN上有很详细的解释。3.声明:声明分为变量声明和函数声明。Expressions中函数表达式的例子写成如下。constparser=tokens=>{//声明一个全时指针,它会一直存在letcurrent=-1;//声明一个临时存储栈,用于存放临时指针consttem=[];//指针指向的当前tokenlettoken=代币[当前];constparseDeclarations=()=>{//暂存当前指针setTem();//将指针移回next();//如果字符为'const',则为声明if(token.type==='identifier'&&token.value==='const'){constdeclarations={type:'VariableDeclaration',kind:token.value};next();//const后面要跟变量,否则会报错reportedif(token.type!=='identifier'){thrownewError('ExpectedVariableafterconst');}//我们得到了变量名declarations.identifierName=token.value;next();//如果后面跟着'=',后面应该跟一个表达式或者常量对,多余判断的代码忽略,直接解析函数表达式if(token.type==='operator'&&token.value==='='){declarations.init=parseFunctionExpression();}returndeclarations;}};constparseFunctionExpression=()=>{next();letinit;//如果'='后面是括号或者字符,基本判断是一个表达式if((token.type==='parens'&&token.valuee==='(')||token.type==='identifier'){setTem();next();while(token.type==='identifier'||token.type===','){next();}//如果括号后面是箭头,则判断为箭头函数表达式if(token.type==='parens'&&token.value===')'){next();if(token.type==='ArrowFunctionExpression'){init={type:'ArrowFunctionExpression',params:[],body:{}};backTem();//解析箭头函数init的参数.params=parseParams();//解析箭头函数的函数体init.body=parseExpression();}else{backTem();}}}returninit;};constparseParams=()=>{constparams=[];if(token.type==='parens'&&token.value==='('){next();while(token.type!=='parens'&&token.value!==')'){if(token.type==='identifier'){params.push({type:token.type,identifierName:token.value});}next();}}returnparams;};constparseExpression=()=>{next();letbody;while(token.type==='ArrowFunctionExpression'){next();}//如果以(或variable开头,则不是BlockStatement,我们用二进制表达式解析if(token.type==='identifier'){body={type:'BinaryExpression',left:{type:'identifier',identifierName:token.value},operator:'',right:{type:'',identifierName:''}};next();if(token.type==='operator'){body.operator=token.value;}next();if(token.type==='identifier'){body.right={type:'identifier',identifierName:token.value};}}returnbody;};//指针后移函数constnext=()=>{do{++current;token=tokens[current]?tokens[current]:{type:'eof',value:''};}while(token.type==='whitespace');};//指针暂存函数constsetTem=()=>{tem.push(current);};//指针回退函数constbackTem=()=>{current=tem.pop();token=tokens[current];};constast={type:'Program',body:[]};while(current