用途
-
代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等
- 如JSLint、JSHint对代码错误或风格的检查,发现一些潜在的错误
- IDE的错误提示、格式化、高亮、自动补全等等
-
代码混淆压缩
- UglifyJS2等
-
优化变更代码,改变代码结构使达到想要的结构
- 代码打包工具webpack、rollup等等
- CommonJS、AMD、CMD、UMD等代码规范之间的转化
- CoffeeScript、TypeScript、JSX等转化为原生Javascript
JavaScript Parser
- JavaScript Parser,把js源码转化为抽象语法树的解析器。
- 浏览器会把js源码通过解析器转为抽象语法树,再进一步转化为字节码或直接生成机器码。
- 一般来说每个js引擎都会有自己的抽象语法树格式,Chrome的v8引擎,firefox的SpiderMonkey引擎等等,MDN提供了详细SpiderMonkey AST format的详细说明,算是业界的标准。常用的:
- esprima
- traceur
- acorn
- shift
解析过程
AST整个解析过程分为两个步骤
- 分词:将整个代码字符串分割成语法单元数组
- 语法分析:建立分析语法单元之间的关系
语法单元
Javascript 代码中的语法单元主要包括以下这么几种
- 关键字:
const、let、var等 - 标识符:可能是一个变量,也可能是 if、else 这些关键字,又或者是 true、false 这些常量
- 运算符
- 数字
- 空格
- 注释
let jsx = `let element=<h1>hello</h1>`; function lexical(code) { const tokens=[]; for (let i=0;i<code.length;i++){ let char=code.charAt(i); if (char == '=') { tokens.push({ type: 'operator', value:char }); } if (char=='<') { const token={ type: 'JSXElement', value:char } tokens.push(token); let isClose = false; for (i++;i<code.length;i++){ char=code.charAt(i); token.value+=char; if (char=='>') { if (isClose) { break; } else { isClose=true; } } } continue; } if (/[a-zA-Z\$\_]/.test(char)) { const token={ type: 'Identifier', value:char } tokens.push(token); for (i++;i<code.length;i++){ char=code.charAt(i); if (/[a-zA-Z\$\_]/.test(char)) { token.value+=char; } else { i--; break; } } continue; } if (/\s/.test(char)) { const token={ type: 'whitespace', value:char } tokens.push(token); for (i++;i<code.length;i++){ char=code.charAt[i]; if (/\s/.test(char)) { token.value+=char; } else { i--; break; } } continue; } } return tokens; } let result=lexical(jsx); console.log(result);