咱們都知道,js
老是一直存在着兼容性問題,雖然其餘語言也存在着兼容性問題,好比c++
、java
,但那種兼容性是新特性在舊版本上的不兼容,js
則存在着各類奇形怪哉的不兼容。這其中有着很是複雜的歷史和時代的緣由,並不加以累述。而解決兼容性問題的方法在之前只存在一種,那就是polyfill
。先說什麼是polyfill
,好比咱們想要用數組的一個新的方法includes
,在較新版本的瀏覽器下,能夠直接使用:前端
可是在舊的瀏覽器下,好比ie10
,就會報錯:java
這種狀況下咱們能夠經過自定義一個方法來解決:react
function includesPolyfill(){ if(!Array.prototype.includes){ Array.prototype.includes=function(element){ for(var i=0; i<this.length; i++){ if(this[i]===element)return true } return false } } }
這裏定義一個簡單的方法,添加到Array.prototype
上,爲了簡單,並無作太多的異常檢測,接着在代碼中引入以上方法並優先執行,就能夠作到在不兼容這個方法的js
環境總直接調用Array.protorype.includes
方法了:webpack
這就是polyfill
,可是polyfill
有其侷限性,對於能夠用舊的方法實現的新特性,可使用polyfill
來解決,好比Array.prototype.includes
,可是,對於一些沒法使用舊方法實現的新特性、新語法,好比箭頭函數
、const
之類的,polyfill
就無能爲力了,這個時候須要使用另外一種方法:預編譯
,或者說是語法轉換
。c++
在以前的js
開發中,是沒有預編譯這個流程的,擼完js
就直接部署了,可是隨着前端工程化的推動,預編譯也就出現了,特別是typescript
之類的語言出現之後,編碼和發佈就再也不是同一種方式了。es6
如今在發佈以前,老是須要打包,而打包有許多的流程,好比資源整合、代碼優化、壓縮混淆...而在其中對代碼的操做上,咱們能夠將新的語法轉化成舊的語法來達到對新語法的支持。web
簡單的說就是,新語法
->編譯器
->舊語法
。typescript
編譯器的做用就是將輸入的源碼中的新特性轉化成就語法,說白了就是字符串處理,好比對箭頭函數
的處理:var add=(num1, num2)=>num1+num2
,這段代碼在不兼容箭頭函數
的環境中,好比ie10
,是沒法執行的npm
可是咱們能夠經過語法轉化、編譯處理,將源碼轉化成var add=function(num1, num2){return num1+num2}
,這樣在不支持箭頭函數的瀏覽器中就能夠執行了json
如今來實現一個簡單的編譯器,固然只支持箭頭函數
function translate(src){ let [_, name, args, body]=src.match(/\((.+)\)=>(.+)/) return `function ${name}(${args}){return ${body}}` }
爲了簡單,只是使用簡單的正則提取來作實驗,而且不作任何異常處理
translate('var add=(num1, num2)=>num1+num') // var add=function(num1, num2){return num1+num2}
將轉化結果保存成文件,就能夠在不兼容箭頭語法的環境中使用了。甚至咱們能夠在瀏覽器中嵌入這個編譯器,將源碼編譯以後使用Function
構造函數或者eval
來執行,達到執行新語法的做用,這種狀況下,稱爲運行時編譯器
,固然通常不會這麼用。
babel
很明顯,不可能本身寫這麼一個編譯器,那還要不要作項目了?這時候只能藉助社區的力量了,babel
就是這麼一個東西,接下來將會使用babel
來解析箭頭函數
初始化一個項目
$ mk babel-demo $ cd babel-demo $ npm init -y
安裝babel
:
注意:(babel7
之後babel
相關的庫基本都是放在@babel
命名空間下)
$ npm install --save-dev @babel/core @babel/cli @babel/plugin-transform-arrow-functions
@babel/core
:核心庫@babel/cli
:命令行工具@babel/plugin-transform-arrow-functions
:箭頭函數語法轉化插件編寫代碼:
var add=(num1, num2)=>num1+num2
使用babel
解析
$ npx babel --plugins @babel/plugin-transform-arrow-functions index.js -o bundle.js
上面命令的意思是將index.js
使用babel
轉化,並將結果放到bundle.js
中,執行以後,將會生成bundle
--plugins
:爲此次轉化添加插件支持-o
:輸出文件查看轉化結果
查看新生成的bundle.js
,能夠發現,箭頭函數
被轉化成了普通的funciton
, 在任何環境中都支持。
var add = function (num1, num2) { return num1 + num2; };
polyfill
,也能夠經過語法轉化來達到兼容。babel
配置文件很明顯,使用babel cli
的侷限性很大,容易出錯、不直觀、繁瑣等,因此babel
仍是支持配置文件的方式:
.babelrc
方式
在項目新建.babelrc
文件,並使用JSON
語法配置
{ "presets": [...], "plugins": [...] }
直接寫在package.json
的babel
節點
{ "name": "my-package", "version": "1.0.0", "babel": { "presets": [ ... ], "plugins": [ ... ], } }
babel.config.js
方式
module.exports = function () { const presets = [ ... ]; const plugins = [ ... ]; return { presets, plugins }; }
兩種方式大同小異,區別就是一個是動態的,一個是靜態的,推薦小項目就用.babelrc
,大項目就使用babel.config.js
babel
配置之plugin
plugin
是babel
中很重要的概念,能夠說,plugin
纔是構成babel
擴展性的核心,各類各樣的plugin
構成了babel
的生態,能夠在這裏看一些babel
的插件列表。
.babelrc
配置文件中配置插件
{ "plugins": ["@babel/plugin-transform-arrow-functions"] }
這時候咱們再執行npx babel index.js -o bundle.js
,就能夠不指定plugin
也能正常轉化箭頭函數了
若是一個plugin
能夠配置參數,則能夠這麼配置:
{ "plugins": [ ["@babel/plugin-transform-arrow-functions", { "spec": true }] ] }
babel
配置之preset
在一個項目中,咱們老是要配置一大堆的插件,這個時候,就是preset
出馬的時候了,那什麼是preset
呢?其實就是預置插件列表
了,引入了一個preset
就包含了一個系列的plugin
好比preset-react
就包含了如下插件:
@babel/plugin-syntax-jsx
@babel/plugin-transform-react-jsx
@babel/plugin-transform-react-display-name
.babelrc
配置preset-react
{ "presets": ["@babel/preset-react"] }
若是有配置項,就醬:
{ "presets": [ [ "@babel/preset-react", { "pragma": "dom", // default pragma is React.createElement "pragmaFrag": "DomFrag", // default is React.Fragment "throwIfNamespace": false // defaults to true } ] ] }
babel
和webpack添加webpack.config.js
const path=requrie('path') module.exports={ entry:path.resolve(__dirname, 'index.js'), output:{ path: path.resolve(__dirname, 'dist'), filename:'bundle.js' }, module: { rules: [ { test: /\.js$/, use: 'babel-loader' } ] }
- 添加相關依賴
$ npm install --save-dev webpack webpack-cli babel-loader ``` - `webpack`:`webpack`核心庫 - `webpack-cli`:`webpack`命令行工具 - `babel-loader`:`babel`的`webpack loader`
打包
$ npm webpack
查看編譯結果
省略無關的東西,能夠看到,箭頭函數
也被轉化成了function
/***/ "./index.js": /*!******************!*\ !*** ./index.js ***! \******************/ /*! no static exports found */ /***/ (function(module, exports) { eval("let add = function (num1, num2) {\n return num1 + num2;\n};\n\nmodule.exports = add;\n\n//# sourceURL=webpack:///./index.js?"); /***/ }) /******/ });
es6
支持es6
可使用@babel/present-env
來代替一系列的東西,還有許多的配置像,好比兼容的瀏覽器版本,具體能夠看這裏
安裝依賴包
$ npm install --save-dev @babel/preset-env
配置
{ "plugins": ["@babel/present-env"] }
打包
$ npm webpack
查看效果
/***/ "./index.js": /*!******************!*\ !*** ./index.js ***! \******************/ /*! no static exports found */ /***/ (function(module, exports) { eval("let add = function (num1, num2) {\n return num1 + num2;\n};\n\nmodule.exports = add;\n\n//# sourceURL=webpack:///./index.js?"); /***/ }) /******/ });
這只是babel
功能的一個小覽,瞭解一下babel
的基本使用和一些概念而已。