先拋個問題,JavaScript 是一門編譯型語言仍是解釋型語言?css
const module1 = require('module1')
import modul2 from 'module2'
const result = 123
複製代碼
咱們在項目會寫不少這種依賴引入,那 Webpack 獲取這段代碼的時候,它應該怎麼去識別它?有的同窗就大腿一拍,這還不簡單,用正則來判斷下不就好,簡單的確定能夠,可是複雜,大段替換,單單正則是搞不定的,那們想一想,大學有一門課叫 編譯原理,把高級語言編譯成機器能識別的,編譯最開始就是 掃描你的代碼,抽象成一顆語法樹,而後進行詞法分析,那這個樹就叫 抽象語法樹,簡稱AST,Babel 把 const
專換成 var
就是利用 這個特性, 把代碼轉換成 AST,而後處理這顆 AST 樹,處理完成,而後又生成 code,一樣 Webpack 處理 require,import
依賴,也是在遍歷 AST 樹, 今天咱們就聊下 AST前端
現代前端是離不開AST,咱們用到的React,Vue,Angular,小程序
,這些框架本質上最後都是轉換成被瀏覽器能識別的 JavaScript 代碼,它們均可以理解成一種 DSL ,你會了你能夠寫一個本身的框架,比方叫avr
,語法來個三不像,也很好晚,流行的 mpvue,taro,react-netive
,都是在處理 AST,專換成你須要的代碼,因此掌握AST很是重要,AST這一層大部分是框架處理,通常開發接觸不到,致使不少人對AST都很陌生,這篇的目的是讓你們大概瞭解下 AST,不會深刻去寫AST,對AST感興趣的能夠關注我下,後面我會寫個三不像的avr
框架,詳細介紹 ASTvue
先來個最簡單的語法,咱們把 const test = 123
轉換成 var test = 123
,看代碼node
const acron = require('acorn')
const traverse = require("ast-traverse");
const escodegen = require('escodegen')
const code = `const test = 123`
let ast = acron.parse(code)
traverse(ast, {
pre: function (node, parent, prop, idx) {
if (node.kind == 'const') {
node.kind = 'var'
}
}
})
let esCode = escodegen.generate(ast)
console.log(esCode)
複製代碼
let ast = acron.parse(code)
會把代碼轉換成 一個tree的數據類型,tree的截圖以下react
你們能夠看到 ast 其實就是對代碼文本的一種抽象,經過 type來標記,咱們要作的是 就是遍歷這顆 tree,把 const
替換成 let
,就行了,而後在把 ast 轉換成 code,代碼很是簡單,能夠本身跑一下webpack
ast 語法簡單的介紹下,網上又不少的詳細的介紹, 各個框架都提供了一個 對應的 *.loader
插件,這些loader 就是把框架的DSL轉換成 JavaScript,Eslint,postcss,這些都是用的AST,咱們腦洞開一下,有了 AST 咱們是否是能夠把 React,Vue 相互轉換,定義本身公司獨有的語法,折騰本身的框架,定義本身的 sass,批量替換老的API,AST 就像手術刀,底層處理代碼,很值得深刻學習,web
回到 Webpack,在第一篇裏,咱們在Webpack 整個流程裏講過,Webpack 把每一個 文件都當作一個個Module,Module上的這些 require,import
依賴,也是經過 ast來判斷的 依賴,而後經過 Resolve來加載這些模塊,chrome
那咱們日常寫的語法常見的有下面這樣的小程序
// webpack.config.js
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
}
}
};
// main.js
const module1 = require('module1')
import modul2 from 'module2'
import util from '../../util/'
import util from '@/util'
import '../style/main.css'
複製代碼
各類依賴 文件路徑處理須要 resove的,Webpack 把這個獨立出來了一個庫 叫 enhanced-resolve
,下篇就講下 resolve 實現瀏覽器
那回到第一個問題 JavaScript 是一門編譯型語言仍是解釋型語言?
JavaScript 是一門編譯型語言,只不過 編譯時間很是短,給人感受是解釋型語言
sum(1,2)
function sum(a,b){
return a + b
}
複製代碼
若是是解釋型語言,代碼一行行的讀,這段代碼是要報錯的,但沒有報錯,我門說這個是函數提高,實際上就是 瀏覽器的編譯過程 若是你喜歡也能夠關注個人 公衆號 「chromedev」