前端的發展總會讓咱們眼前一亮,這又有什麼規範出來了,上個規範我還沒理解透徹呢。但無論將來怎麼發展,瞭解歷史仍是很是重要的,以史爲鏡,能夠知得失。知道了規範的發展歷史,才能更好的瞭解目前的規範。前端
看着上面的script標籤,是否是有一種很熟悉的感受。經過script引入你想要的資源,從上到下的順序,這其中順序是很是重要的,資源的加載前後決定你的代碼是否可以跑的下去。固然咱們尚未加入defer和async屬性,否則加載的邏輯會更加複雜。這裏引入的資源仍是算少的,過多的script標籤會形成過多的請求。同時項目越大,到最後依賴會愈來愈複雜,而且難以維護,依賴模糊,請求過多。全局污染的可能性就會更大。那麼問題來了,如何造成獨立的做用域?java
defer要等到整個頁面在內存中正常渲染結束(DOM 結構徹底生成,以及其餘腳本執行完成),纔會執行;async一旦下載完,渲染引擎就會中斷渲染,執行這個腳本之後,再繼續渲染。一句話,defer是「渲染完再執行」,async是「下載完就執行」。另外,若是有多個defer腳本,會按照它們在頁面出現的順序加載,而多個async腳本是不能保證加載順序的。node
當即執行函數(immediately-invoked function expression),簡稱IIFE,實際上是一個javaScript函數。能夠在函數內部定義方法以及私有屬性,至關於一個封閉的做用域。例以下面的代碼:webpack
let module = (function(){
let _private = 'myself';
let fun = () =>{
console.log(_private)
}
return {
fun:fun
}
})()
module.fun()//myself
module._private//undefined
複製代碼
以上代碼即可以造成一個獨立的做用域,必定程度上能夠減小全局污染的可能性。這種寫法但是現代模塊化的基石。雖然可以定義方法,可是不能定義屬性,這時候各類前端規範就陸續登場了。git
最早遵照CommonJS規範是node.js。此次變革讓服務端也能用js爽歪歪的寫了,咱們的javaScript並不止於瀏覽器,服務端也能分一杯羹,被人稱爲模塊化的第一座里程碑。想一想長征二萬五,第一座里程碑在哪裏?es6
// 刪除指定模塊的緩存
delete require.cache[moduleName];
// 刪除全部模塊的緩存
Object.keys(require.cache).forEach(function(key) {
delete require.cache[key];
})
複製代碼
exports只是一個變量,指向module.exports,也就是exports只是一個引用而已。因此對外輸出模塊的時候,咱們就能夠經過exports添加方法和和屬性。經過module.exports對外輸出其實也是讀取module.exports的變量。可是使用exports時要很是的當心,由於稍不注意就會切斷和module.exports的聯繫。例如:github
exports = function(x) {console.log(x)};
複製代碼
上面的代碼運行以後,exports再也不指向module.exports。若是你難以區分清楚,通常最好就別用exports,只使用module.exports就行。web
require.mainAPI就有這樣的做用,若是模塊是直接執行,那麼這時require.main屬性就指向模塊自己。例以下面:ajax
require.main === module
複製代碼
咱們知道客戶端(瀏覽器)加載資源主要是經過網絡獲取,通常本地讀取的比較少,而node.js主要是用於服務器編程,模塊文件通常都存在於本地硬盤上,而後I/O讀取是很是快速的,因此即便是同步加載也是可以適用的,而瀏覽器加載資源必須經過異步獲取,好比常見的ajax請求,這時候AMD規範就很是合適了,能夠異步加載模塊,容許回調函數。express
每一個規範的興起背後總有一些緣由,requirejs的流行是由於commonjs未能知足咱們須要的效果,sea.js被創造的緣由也是由於requirejs不能知足一些場景。
- | AMD | CMD |
---|---|---|
原理 | define(id ?,dependencies ?,factory)定義了一個單獨的函數「define」。id爲要定義的模塊。依賴經過dependencies傳入factory是一個工廠參數的對象,指定模塊的導出值。 | CMD規範與AMD相似,並儘可能保持簡單,可是更多的與common.js保持兼容性。 |
優勢 | 特別適用於瀏覽器環境的異步加載 ,且能夠並行加載。依賴前置,提早執行。 定義模塊時就能清楚的聲明所要依賴的模塊 | 依賴就近,延遲執行。 按需加載,須要用到時再require |
缺點 | 開發成本較高,模塊定義方式的語義交爲難理解,不是很符合經過的模塊化思惟方式。 | 依賴SPM打包,模塊的加載主觀邏輯交重。 |
體現 | require.js | sea.js |
ES6的模塊不是對象,import語法會被JavaScript引擎靜態分析,請注意,這是一個很重要的功能,咱們一般使用commonjs時,代碼都是在運行時加載的,而es6是在編譯時就引入模塊代碼,固然咱們如今的瀏覽器尚未這麼強大的功能,須要藉助各種的編譯工具(webpack)才能正確的姿式來使用es6的模塊化的功能。也正由於可以編譯時就引入模塊代碼,因此使得靜態分析就可以實現了。
靜態化編譯 若是可以靜態化,編譯的時候就能肯定模塊的依賴關係,以及輸出和輸入的變量,而後CommonJS和AMD以及CMD都只能在運行代碼時才能肯定這些關係。
不須要特殊的UMD模塊化格式 再也不須要UMD模塊的格式,未來服務器和瀏覽器都會支持ES6模塊格式。目前各類工具庫(webpack)其實已經作到這一點了。
目前的各種全局變量均可以模塊化 好比navigator如今是全局變量,之後就能夠模塊化加載。這樣就再也不須要對象做爲命名空間。
function fun(){
export default 'hello' //SyntaxError
}
複製代碼
fun()
import {fun} from 'myModule';
複製代碼
上面的代碼import的執行早於fun調用,緣由是import命令是編譯階段執行的,也就是在代碼運行以前。
export default就是輸出一個叫default的變量或方法,而後系統容許你爲它取任意名字。因此,你能夠看到下面的寫法。
//modules.js
function add(x,y){
return x*y
}
export {add as default};
//等同於
export default add;
//app.js
import {default add foo} from 'modules';
//等同於
import foo from 'modules'
複製代碼
這是由於export default命令其實只是輸出一個叫作default的變量,因此它後面不能跟變量聲明語句。
利用頂層的this等於undefined這個語法點,能夠偵測當前代碼是否在 ES6 模塊之中。
const isNotModuleScript = this !== undefined;
複製代碼
若是大神您想繼續探討或者學習更多知識,歡迎加入QQ或者微信一塊兒探討:854280588