摘要:簡(jiǎn)單來(lái)說(shuō)就是一個(gè)對(duì)于代碼的一個(gè)編譯過(guò)程,進(jìn)行了詞法分析與語(yǔ)法分析的過(guò)程。轉(zhuǎn)換對(duì)于進(jìn)行變換一系列的操作,接受得到并通過(guò)對(duì)其進(jìn)行遍歷,在此過(guò)程中進(jìn)行添加更新及移除等操作。而模塊則是將三者結(jié)合使得對(duì)外提供的做了一個(gè)簡(jiǎn)化。
直奔主題
對(duì)于js,AST能干什么?
babel將es6轉(zhuǎn)es5
mpvue、taro等將js轉(zhuǎn)為小程序
定制插件刪除注釋、console等
ps: 本文只探討AST的概念以及使用,編譯原理的其他知識(shí)不做太多描述
工具庫(kù)@babel/core
用來(lái)解析AST以及將AST生成代碼
@babel/types
構(gòu)建新的AST節(jié)點(diǎn)
前置知識(shí) - 編譯原理概述毫無(wú)疑問(wèn)js是一個(gè)解釋型語(yǔ)言,有疑問(wèn)可以參考這篇文章
所以這里只簡(jiǎn)單描述一下babel的編譯過(guò)程(大霧),有興趣了解編譯型語(yǔ)言詳細(xì)編譯過(guò)程的可以看這本 《編譯原理》
和編譯器類似,babel 的轉(zhuǎn)譯過(guò)程也分為三個(gè)階段,這三步具體是:生成AST解析 Parse
將代碼解析生成抽象語(yǔ)法樹(shù)( 即AST ),也就是計(jì)算機(jī)理解我們代碼的方式(擴(kuò)展:一般來(lái)說(shuō)每個(gè) js 引擎都有自己的 AST,比如熟知的 v8,chrome 瀏覽器會(huì)把 js 源碼轉(zhuǎn)換為抽象語(yǔ)法樹(shù),再進(jìn)一步轉(zhuǎn)換為字節(jié)碼或機(jī)器代碼),而 babel 則是通過(guò)babylon 實(shí)現(xiàn)的 。簡(jiǎn)單來(lái)說(shuō)就是一個(gè)對(duì)于 JS 代碼的一個(gè)編譯過(guò)程,進(jìn)行了詞法分析與語(yǔ)法分析的過(guò)程。轉(zhuǎn)換 Transform
對(duì)于 AST 進(jìn)行變換一系列的操作,babel 接受得到 AST 并通過(guò) babel-traverse 對(duì)其進(jìn)行遍歷,在此過(guò)程中進(jìn)行添加、更新及移除等操作。生成 Generate
將變換后的 AST 再轉(zhuǎn)換為 JS 代碼, 使用到的模塊是 babel-generator。而 babel-core 模塊則是將三者結(jié)合使得對(duì)外提供的API做了一個(gè)簡(jiǎn)化。
demo.js是我隨便copy來(lái)的一段代碼
isLeapYear() function isLeapYear(year) { const cond1 = year % 4 == 0; //條件1:年份必須要能被4整除 const cond2 = year % 100 != 0; //條件2:年份不能是整百數(shù) const cond3 = year % 400 ==0; //條件3:年份是400的倍數(shù) const cond = cond1 && cond2 || cond3; console.log(cond) if(cond) { alert(year + "是閏年"); return true; } else { alert(year + "不是閏年"); return false; } }
現(xiàn)在我要把它轉(zhuǎn)成AST,這里使用@babel/core來(lái)解析,它提供了一個(gè)parse方法來(lái)將代碼轉(zhuǎn)化為AST。
parse.ts就是我的解析工具
import * as fs from "fs" import * as path from "path" import { parse} from "@babel/core" const js_path = path.resolve(__dirname, "../demo.js") let code = fs.readFileSync(js_path, { encoding: "utf-8" }) const js_ast = parse(code) console.log(js_ast)
可以看到AST結(jié)果如下:
結(jié)果太長(zhǎng)就不一一解析了,只說(shuō)type屬性,就表示了這一行代碼做了什么,VariableDeclaration就表示這是一句聲明語(yǔ)句, CallExpression則代表這是一個(gè)調(diào)用函數(shù)的語(yǔ)句
將AST轉(zhuǎn)回代碼@babel/core提供了一個(gè)transform方法,輸入代碼和修改代碼的規(guī)則,輸出修改過(guò)的AST,它看起來(lái)是這樣的:
const ArrowPlugins = { visitor: { VariableDeclaration(path: NodePath) { // ... }, CallExpression(path: NodePath) { // ... } } } const d = transform(code, { plugins: [ ArrowPlugins ] })
當(dāng)命中對(duì)應(yīng)的type時(shí)就會(huì)走進(jìn)相應(yīng)的回調(diào)函數(shù),接下來(lái)寫(xiě)個(gè)小
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/105471.html
摘要:為什么要談抽象語(yǔ)法樹(shù)如果你查看目前任何主流的項(xiàng)目中的,會(huì)發(fā)現(xiàn)前些年的不計(jì)其數(shù)的插件誕生。什么是抽象語(yǔ)法樹(shù)估計(jì)很多同學(xué)會(huì)和圖中的喵一樣,看完這段官方的定義一臉懵逼。它讀取我們的代碼,然后把它們按照預(yù)定的規(guī)則合并成一個(gè)個(gè)的標(biāo)識(shí)。 前言 首先,先說(shuō)明下該文章是譯文,原文出自《AST for JavaScript developers》。很少花時(shí)間特地翻譯一篇文章,咬文嚼字是件很累的事情,實(shí)在...
摘要:前言虛擬語(yǔ)法樹(shù)是解釋器編譯器進(jìn)行語(yǔ)法分析的基礎(chǔ)也是眾多前端編譯工具的基礎(chǔ)工具比如等對(duì)于由于前端輪子眾多人力過(guò)于充足早已經(jīng)被人們玩膩了光是語(yǔ)法分析器就有等等若干種并且也有了的社區(qū)標(biāo)準(zhǔn)這篇文章主要介紹如何去寫(xiě)一個(gè)解析器但是并不是通過(guò)分析而是通過(guò) 前言 虛擬語(yǔ)法樹(shù)(Abstract Syntax Tree, AST)是解釋器/編譯器進(jìn)行語(yǔ)法分析的基礎(chǔ), 也是眾多前端編譯工具的基礎(chǔ)工具, 比如...
摘要:前言虛擬語(yǔ)法樹(shù)是解釋器編譯器進(jìn)行語(yǔ)法分析的基礎(chǔ)也是眾多前端編譯工具的基礎(chǔ)工具比如等對(duì)于由于前端輪子眾多人力過(guò)于充足早已經(jīng)被人們玩膩了光是語(yǔ)法分析器就有等等若干種并且也有了的社區(qū)標(biāo)準(zhǔn)這篇文章主要介紹如何去寫(xiě)一個(gè)解析器但是并不是通過(guò)分析而是通過(guò) 前言 虛擬語(yǔ)法樹(shù)(Abstract Syntax Tree, AST)是解釋器/編譯器進(jìn)行語(yǔ)法分析的基礎(chǔ), 也是眾多前端編譯工具的基礎(chǔ)工具, 比如...
摘要:的抽象語(yǔ)法樹(shù)中可能如下圖所示代碼生成將轉(zhuǎn)換為可執(zhí)行代碼的過(guò)程被稱為代碼生成。如果是,編譯器會(huì)忽略該聲明,繼續(xù)進(jìn)行編譯,否則它會(huì)要求在當(dāng)前作用域的集合中聲明一個(gè)新的變量,并命名為。 在學(xué)習(xí) javascript 的過(guò)程中,我們第一步最應(yīng)該了解和掌握的就是作用域,與之相關(guān)還有程序是怎么編譯的,變量是怎么查找的,js 引擎是什么,引擎和作用域的關(guān)系又是什么,這些是 javascript 這門(mén)...
閱讀 1457·2021-09-28 09:43
閱讀 4352·2021-09-04 16:41
閱讀 1983·2019-08-30 15:44
閱讀 3879·2019-08-30 15:43
閱讀 836·2019-08-30 14:21
閱讀 2088·2019-08-30 11:00
閱讀 3381·2019-08-29 16:20
閱讀 2012·2019-08-29 14:21