前端的模塊化之路經歷了漫長的過程,想詳細瞭解的小夥伴能夠看浪裏行舟大神寫的前端模塊化詳解(完整版),這裏根據幾位大佬們寫的文章,將模塊化規範部分作了彙總和整理,但願讀完的小夥伴能有些收穫,也但願以爲有用的小夥伴能夠點個贊,筆芯。javascript
Node 應用由模塊組成,採用 CommonJS 模塊規範。每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。在服務器端,模塊的加載是運行時同步加載的;在瀏覽器端,模塊須要提早編譯打包處理。前端
CommonJS規範加載模塊是同步的,也就是說,只有加載完成,才能執行後面的操做。java
基本語法:git
module.exports = value
或 exports.xxx = value
require(xxx)
,若是是第三方模塊,xxx爲模塊名;若是是自定義模塊,xxx爲模塊文件路徑可是,CommonJs有一個重大的侷限使得它不適用於瀏覽器環境,那就是require
操做是同步的。這對服務器端不是一個問題,由於全部的模塊都存放在本地硬盤,能夠同步加載完成,等待時間就是硬盤的讀取時間。可是,對於瀏覽器,這倒是一個大問題,由於模塊都放在服務器端,等待時間取決於網速的快慢,可能要等很長時間,瀏覽器處於」假死」狀態。es6
所以,瀏覽器端的模塊,不能採用」同步加載」(synchronous),只能採用」異步加載」(asynchronous),這就是AMD規範誕生的背景。github
特色:非同步加載模塊,容許指定回調函數,瀏覽器端通常採用AMD規範編程
表明做:require.js瀏覽器
用法:緩存
//定義沒有依賴的模塊 define(function(){ return 模塊 }) //定義有依賴的模塊 define(['module1', 'module2'], function(m1, m2){ return 模塊 }) //引入使用模塊 require(['module1', 'module2'], function(m1, m2){ //使用m1/m2 })
特色:專門用於瀏覽器端,模塊的加載是異步的,模塊使用時纔會加載執行服務器
表明做:Sea.js
用法:
//定義沒有依賴的模塊 define(function(require, exports, module){ exports.xxx = value module.exports = value }) //定義有依賴的模塊 define(function(require, exports, module){ //引入依賴模塊(同步) var module2 = require('./module2') //引入依賴模塊(異步) require.async('./module3', function (m3) { }) //暴露模塊 exports.xxx = value }) //引入使用模塊 define(function (require) { var m1 = require('./module1') var m4 = require('./module4') m1.show() m4.show() })
AMD和CMD最大的區別是對依賴模塊的執行時機處理不一樣,而不是加載的時機或者方式不一樣,兩者皆爲異步加載模塊。
AMD依賴前置,js能夠方便知道依賴模塊是誰,當即加載;
而CMD就近依賴,須要使用把模塊變爲字符串解析一遍才知道依賴了那些模塊,這也是不少人詬病CMD的一點,犧牲性能來帶來開發的便利性,實際上解析模塊用的時間短到能夠忽略。
一句話總結:
二者都是異步加載,只是執行時機不同。AMD是依賴前置,提早執行,CMD是依賴就近,延遲執行。
UMD是AMD和CommonJS的糅合:
AMD模塊以瀏覽器第一的原則發展,異步加載模塊。
CommonJS模塊以服務器第一原則發展,選擇同步加載,它的模塊無需包裝(unwrapped modules)。
這迫令人們又想出另外一個更通用的模式UMD (Universal Module Definition)。但願解決跨平臺的解決方案。
UMD先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js
模塊模式。
在判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。
(function (window, factory) { if (typeof exports === 'object') { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define(factory); } else { window.eventUtil = factory(); } })(this, function () { //module ... });
ES6 模塊的設計思想是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時肯定這些東西。好比,CommonJS 模塊就是對象,輸入時必須查找對象屬性。
ES6 Module默認目前尚未被瀏覽器支持,須要使用babel,在平常寫demo的時候常常會顯示這個錯誤:
ES6模塊使用import
關鍵字導入模塊,export
關鍵字導出模塊:
/** 導出模塊的方式 **/ var a = 0; export { a }; //第一種 export const b = 1; //第二種 let c = 2; export default { c }//第三種 let d = 2; export default { d as e }//第四種,別名 /** 導入模塊的方式 **/ import { a } from './a.js' //針對export導出方式,.js後綴可省略 import main from './c' //針對export default導出方式,使用時用 main.c import 'lodash' //僅僅執行lodash模塊,可是不輸入任何值
export {<變量>}
這種方式通常稱爲 命名式導出 或者 具名導出,導出的是一個變量的引用。export default
這種方式稱爲 默認導出 或者 匿名導出,導出的是一個值。
舉例:
// a.js let x = 10 let y = 20 setTimeout(()=>{ x = 100 y = 200 },100) export { x } export default y // b.js import { x } from './a.js' import y from './a.js' setTimeout(()=>{ console.log(x,y) // 100,20 },100)
① CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。
CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。並且,CommonJS 模塊不管加載多少次,都只會在第一次加載時運行一次,之後再加載,返回的都是第一次運行結果的緩存,除非手動清除系統緩存。
ES6 模塊的運行機制與 CommonJS 不同,JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import
,就會生成一個只讀引用,等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊裏面去取值。換句話說,ES6 的import
有點像 Unix 系統的「符號鏈接」,原始值變了,import
加載的值也會跟着變。所以,ES6 模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
② CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。
CommonJS 加載的是一個對象(即module.exports
屬性),該對象只有在腳本運行完纔會生成。即在輸入時是先加載整個模塊,生成一個對象,而後再從這個對象上面讀取方法,這種加載稱爲「運行時加載」。
例如:
// CommonJS模塊 let { stat, exists, readFile } = require('fs'); // 等同於 let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;
上面代碼的實質是總體加載fs模塊(即加載fs的全部方法),生成一個對象(_fs),而後再從這個對象上面讀取 3 個方法。由於只有運行時才能獲得這個對象,致使徹底沒辦法在編譯時作「靜態優化」。
ES6 模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。經過export
命令顯式指定輸出的代碼,import
時採用靜態命令的形式。即在import
時能夠指定加載某個輸出值,而不是加載整個模塊,這種加載稱爲「編譯時加載」或者「靜態加載」。
// ES6模塊 import { stat, exists, readFile } from 'fs';
上面代碼的實質是從fs模塊加載 3 個方法,其餘方法不加載。即 ES6 能夠在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。固然,這也致使了無法引用 ES6 模塊自己,由於它不是對象。
因爲 ES6 模塊是編譯時加載,使得靜態分析成爲可能。有了它,就能進一步拓寬 JavaScript 的語法,好比引入宏(macro)和類型檢驗(type system)這些只能靠靜態分析實現的功能。
除了靜態加載帶來的各類好處,ES6 模塊還有如下好處:
navigator
對象的屬性。Math
對象),將來這些功能能夠經過模塊提供。Node.js
中運行。不過,依賴SPM打包,模塊的加載邏輯偏重。以上是本篇文章的內容,歡迎你們提出本身的想法,咱們一塊兒學習進步,與君共勉。
前端模塊化詳解(完整版)
ECMAScript 6 入門
近一萬字的ES6語法知識點補充
完全搞清楚javascript中的require、import和export
CommonJS,AMD,CMD,ES6,require 和 import 詳解