在使用JavaScript開發大型項目時,模塊開發概念是一個必須考慮的問題。其目的就是通過命名空間對各類業務對象進行一定的封裝,防止命名沖突。
本篇着重介紹ES6 module中的export和import概念。
1. ES5的模塊支持方案
在ES6之前,JavaScript本身沒有模塊支持,但社區創造了令人印象深刻的解決方案。兩個最重要的(也是不相容的)標准是:AMD 和 CommonJS。
1.1 AMD
說明:AMD,全稱為Asynchronous Module Definition,即異步模塊定義。
特點:其模塊和依賴都可以進行異步加載。
// 定義AMD模塊 define('User/UserGrid', // 模塊ID ['UserM'], // 依賴文件 function(userM) { // 初始化函數,依賴文件以參數形式加入 } ); // 使用AMD模塊 require(['User/UserGrid'], function(userGrid) { } );
1.2 CommonJS
說明:CommonJS模塊規范初衷是用於node.js服務器端,以提供額外的功能,如:IO、文件系統等功能。
特點:
①同步加載;只有加載完成,才能執行后面的操作。
②緩存加載;第一次加載時會把內容存入緩存,以后的加載都是從緩存獲取。
示例:
// math.js(定義模塊) exports.add = function(a, b) { return a + b; }; // app.js(使用模塊) var math = require('./math'); var rs = math.add(1, 2); console.log(rs);
了解更多AMD 與 CommonJS 知識可參考此文章:Writing Modular JavaScript With AMD, CommonJS & ES Harmony
2. ES6 module
ES6 module 結合了CommonJS和AMD的優點:類似CommonJS,具有簡潔的語法,對循環依賴的支持;類似AMD,支持異步加載和有條件的模塊加載。
ES6 module 使用 export 導出模塊的內容,並使用 import 導入模塊的內容。
2.1 瀏覽器原聲支持
使用之前,先看下各瀏覽器對原生ES6 module的支持情況:Chrome61及61+、Edge16及16+版本都已支持
使用方式:
以Chrome為例,在引入ES6 module 的JS文件時,使用屬性 type="module" 即可:
<script type="module" src="js/math.js"></script> <script type="module" src="js/app.js"></script>
2.2 export 導出(定義模塊)
創建ES6模塊時,可使用export關鍵字導出(對外提供)模塊的內容,如函數、對象以及原始變量等等。
export 導出方案有2種:Named exports(命名導出;每個模塊可有多個)和 Default exports(默認導出;每個模塊只能一個)。
1) Named exports 命名導出
說明:使用 export + 名稱 的形式導出模塊的內容。
注意:在 import 導入過程中,需指定這些名稱。
語法:
// 1)聲明時導出 export var myVar1 = 'a'; export let myVar2 = 'b'; export const MY_CONST = 'c'; export function myFunc() {} // 2)聲明后導出 var myVar3 = 'a'; export { myVar3 }; // 3)別名導出 var myVar4 = 'a'; export { myVar4 as myVar };
示例:
// math.js export function add(a, b) { return a + b; } // app.js:導入含有命名導出的模塊時,需要指定成員名稱 import { add } from './math.js'; console.log(add(1, 2)); // => 3 // demo.html <script type="module" src="js/math.js"></script> <script type="module" src="js/app.js"></script>
2) Default exports 默認導出
說明:使用 export default 導出模塊默認的內容,每個模塊只能有一個 export default。
語法:
// 1)聲明時導出 export default expression; export default function () {} // 2)別名設置為default導出 export default function name1() {} export { name1 as default };
示例:默認導出聲明的是一個表達式,通常沒有名字,導入時需指定模塊名稱。
// math.js export function add(a, b) { return a + b; } export default function cube(x) { return x * x * x; } // app.js:導入默認導出的模塊時,需要指定模塊名稱 import cube from './math.js'; console.log(cube(3)); // => 27 // 若想同時導入含有默認導出、命名導出的模塊,只需要導入時用','隔開 // import cube, { add } from './math.js'; // demo.html <script type="module" src="js/math.js"></script> <script type="module" src="js/app.js"></script>
2.3 import 導入模塊
使用 import 可導入創建的模塊。
語法:
// 1)導入模塊的默認導出內容 import defaultExport from 'module-name'; // 2)導入模塊的命名導出內容 import { export1, export2 } from 'module-name'; import { export as alias } from 'module-name'; // 修改別名 import * as name from 'module-name'; // 導入模塊內的所有命名導出內容 // 3)導入模塊的默認導出、命名導出 import defaultExport, { export1, export2 } from 'module-name'; import defaultExport, * as name from 'module-name';
1) 導入默認導出
說明:導入默認導出的模塊時,需要指定模塊名稱
示例:
// math.js export default function cube(x) { return x * x * x; } // app.js:導入默認導出的模塊時,需要指定模塊名稱 import cube from './math.js'; console.log(cube(3)); // => 27
2) 導入命名導出
說明:導入模塊時可使用大括號包含指定命名成員;也可以用 * as moduleName 的形式把此模塊的所有命名導出作為某個對象的成員。
示例:
// math.js export function add(a, b) { return a + b; } // app.js:指定使用math模塊的add命名導出 import { add } from './math.js'; console.log(add(1, 2)); // => 3 // 導入所有的命名導出作為math對象的成員 import * as math from './math.js'; console.log(math.add(1, 2)); // => 3
3) 僅導入模塊
說明:僅導入模塊時,只會執行模塊的全局函數,不會導入任何成員。
示例:
// math.js export function add(a, b) { return a + b; } (function() { console.log('hello math.js'); })(); // app.js import { add } from './math.js'; // => hello math.js
4. 擴展閱讀
ECMAScript 6 modules: the final syntax :http://2ality.com/2014/09/es6-modules-final.html
MDN export :https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
MDN import:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import