CSS
早在 2.1
的版本就提出了 @import
來實現模塊化,可是 JavaScript
直到 ES6
纔出現官方的模塊化方案 ES Module
。儘管早期 JavaScript
語言規範上不支持模塊化,但這並無阻止 JavaScript
的發展。官方沒有模塊化標準,那麼咱們就本身動手建立標準。社區裏的前輩們建立並實現了規範,這些規範即是前端模塊化發展之路上智慧的結晶。javascript
在 2020
年的今天來看,模塊化應該具備如下價值:前端
十年以前,模塊化還只是使用閉包簡單的實現一個命名空間。使用這種解決方式能夠簡單粗暴的處理全局變量和依賴關係等問題。java
關於閉包的概念能夠參考個人另外一篇文章。node
讓咱們把時間追溯到 2009 年 1 月,在這個普通的冬天裏,萬物開始生長。中國南極科學考察站崑崙站落成,成爲南極海拔最高的科學考察站。在 JavaScript
社區中, Mozilla
的工程師 Kevin Dangoor
發起了 CommonJS
的提案。(最初叫ServerJS
)git
再到後來橫空出世的 Node.js
採用 CommonJS
模塊化規範,同時還帶來了 npm
(全球最大的模塊倉庫) 。程序員
nodejs 中模塊的實現並不是徹底按照 CommonJS 的規範來的,而是進行了取捨,並增長了少量特性。es6
CommonJS
規範在服務端表現出色,使得 JavaScript
在服務器端大放異彩,與傳統服務器語言(PHP、Python)等產生抗衡甚至壓倒之勢。程序員們便萌發出了將它移植到瀏覽器端的想法。github
然而因爲CommonJS
的模塊加載是同步的。咱們知道,服務器端加載的模塊從內存或磁盤中加載,耗時基本可忽略。可是在瀏覽器端卻會形成阻塞,白屏時間過長,用戶體驗不夠友好。npm
所以,從CommonJS
中逐漸產生了一些分支,也就是業內熟知的AMD
、CMD
等。瀏覽器
James Burke提出了 AMD
規範,RequireJS
也是他的表明做。他同時開發了 amdefine
(在node中可使用AMD規範的庫)。
AMD
主要是爲了解決 CommonJS
規範在瀏覽器端的不足:
export
只能導出變量,導出函數須要用 module.export
(這一般不符合直覺)AMD
規範定義了一個 define
全局方法用來定義和加載模塊,RequireJS
後期也擴展了 require
全局方法用來加載模塊 。其核心實現是內部的模塊加載器。
@玉伯提出了 sea.js
(CMD規範的實現)。
準確的說 CMD
是 SeaJS
在推廣過程當中對模塊定義的規範化產物。
相比於AMD
的異步加載,CMD
更傾向於懶加載,規範自己也與CommonJS
更貼近。
由於是懶加載機制,因此 sea.js
提供了 seajs.use
方法,來運行已經定義的模塊。全部 define
的回調函數都不會當即執行,而是將全部的回調函數進行緩存,只有 use
以後,以及被 require
的模塊回調纔會執行。
sea.js
只有在 require
的地方,纔會真正執行模塊。RequireJS
會先運行全部的依賴,獲得全部的結果後再執行回調。AMD
是提早執行,CMD
是延遲執行。CMD
推崇依賴就近,AMD
推崇依賴前置。AMD
的 API
一個當多個用,職責單一。CMD
中,每一個API都簡單純粹。來自@玉伯的回答
UMD
是 AMD
和 CommonJS
的綜合產物。AMD
用於瀏覽器,CommonJS
用於服務器。UMD
則是二者的兼容模式,解決了跨平臺問題。
實現原理:if-else
詳情請移步githubUMD
天下大勢,分久必合。
十年以後,官方爸爸推出的 ES6
模塊化方案,一統瀏覽器和服務器。採用了徹底靜態化的方式進行模塊加載。
// 默認導入default模塊 // main.js import name from './module.js' // module.js const name = '前端食堂' export default name
// 若是想導入其餘模塊 // main.js import { name, getName } from './module.js' // module.js export const name = '前端食堂' export const getName = () => name
// 同時導入 // main.js import name, { getName } from './module.js' // module.js const name = '前端食堂' export const getName = () => name export default name
// 重命名 // main.js import * as mod from './module.js' let name = '' name = mod.name name = mod.getName() // module.js export const name = '前端食堂' export const getName = () => name
// 對單獨的變量進行重命名 import { name, getName as getModName }
// 第一種寫法 export const name = '前端食堂' // 第二種寫法 export function getName() { return name } export class Logger { log(...args) { console.log(...args) } } // 第三種寫法 const name = '前端食堂' function getName() { return name } class Logger { log(...args) { console.log(...args) } } export {name, getName, Logger} // 第四種寫法 const name = '前端食堂' export default name
這裏只提供了一些基本語法,更多語法請參考阮一峯老師的 《ECMAScript 6 入門》。
固然,不一樣的規範之中,被規範的語法也有所不一樣,這裏推薦業內公認的語法規範airbnb。
這裏列舉出幾個airbnb
中模塊導出/引入的規範。
1.若是模塊只有一個輸出值,就使用 export default
,若是模塊有多個輸出值,就不使用 export default
, export default
與普通的 export
不要同時使用。
2.模塊導入時不要使用通配符。由於這樣能夠確保你的模塊之中,有一個默認輸出 (export default)
。
// bad import * as myObject from './importModule'; // good import myObject from './importModule';
1.語法 import/export
require/module
2.CommonJS
模塊輸出的是一個值的拷貝(不會隨原始值變化),ES6
模塊輸出的是值的引用(會隨着原始值變化)。
3.CommonJS
模塊是運行時加載,ES6
模塊是編譯時輸出接口。
整天討論這門語言好,或者那門語言壞的人,甚至是可悲的。既悲其一葉障目,更悲其大愚若智的自得心態。 ——《大道至簡》
JavaScrit
至今仍有被人詬病的缺憾之處。但歷史告訴咱們,再多的阻力也阻擋不了真正熱愛它的人們。
感謝爲 JavaScript
模塊化之路貢獻的開發者們。
1.看到這裏了就點個「贊」支持下吧,你的贊
是我創做的動力。
2.關注公衆號「前端食堂」,你的前端食堂,記得按時吃飯!
3.特殊階段,帶好口罩,作好我的防禦。