NodeJS中使用的模塊規範。
根據CommonJS規範,一個單獨的文件就是一個模塊(module)。加載模塊使用require方法,該方法讀取一個文件並執行,最後返回文件內部的module.exports對象。
CommonJS採用同步加載模塊的方式,只有加載完才能執行後面的操做,主要適用於服務端。es6
一、exports與require使用的模塊導入導出規則遵循的是CommonJS(AMD和CMD)規範, 通常在NodeJS(express,koa)中使用,是相對比較先出現的規範,也是目前大多數瀏覽器支持的模塊導入導出規範。typescript
一、一個文件即爲一個module;
二、一個module中有不少字段,例如 id
path
parent
exports
等等,能夠直接在js文件輸出module
便可查看;
三、exports
表示這個module要導出的數據,module.export
默認指向一個空的對象內存;
四、變量exports
默認指向module.exports
(引用傳遞);
五、module
實際上導出的數據是在module.export
這個變量中;express
一、使用require
便可導入另外一模塊中導出的數據;segmentfault
不管模塊exports
的是什麼數據類型,module.exports
與require
指向的是同一塊內存地址,任何一方改變都會影響另外一方的數據(動態)瀏覽器
案例一:緩存
// a.js文件 let aNum = 1; let aArr = [1]; setTimeout(() => { aNum = 11; // 並不會影響module.exports.aNum的值 aArr.push(11); // 會影響module.exports.aArr的值 console.log('1s a模塊改變數據aNum&aArr:'); console.log(`aNum=${aNum},module.exports.aNum=${module.exports.aNum}`); console.log(`aArr=${aArr},module.exports.aArr=${module.exports.aArr}`); }, 1000) setTimeout(() => { console.log(`3s a模塊接受數據:aNum=${module.exports.aNum},aArr=${module.exports.aArr}`); }, 3000) // 如下寫法等價於 // module.exports.aNum = aNum aNum屬於基本類型 值拷貝 // module.exports.aArr = aArr aArr屬於對象 值引用 module.exports = { aNum, aArr }; console.log(`a模塊已導出數據:aNum=${module.exports.aNum},aArr=${module.exports.aArr}`); // b.js文件 const a = require("./commonjs_a"); console.log(`b模塊已接收數據:aNum=${a.aNum},aArr=${a.aArr}`); setTimeout(() => { console.log(`2s b模塊接受數據:aNum=${a.aNum},aArr=${a.aArr}`); a.aNum = 2; a.aArr = [2] console.log(`2s b模塊改變數據:aNum=${a.aNum},aArr=${a.aArr}`); }, 2000) // 輸出結果 a模塊已導出數據:aNum=1,aArr=1 b模塊已接收數據:aNum=1,aArr=1 1s a模塊改變數據aNum&aArr: aNum=11,module.exports.aNum=1 aArr=1,11,module.exports.aArr=1,11 2s b模塊接受數據:aNum=1,aArr=1,11 2s b模塊改變數據:aNum=2,aArr=2 3s a模塊接受數據:aNum=2,aArr=2
一、export與import是ES組織官方退出的模塊化方案,通常在typescript和三大框架(Angular, Vue, React)中比較常見,但目前支持這套規範的客戶端瀏覽器比較少,因此一般狀況下代碼都要通過Babel轉換成目前瀏覽器能支持的,也就是exports和require那一套。框架
一、不管導出數據是什麼類型的,export
導出的都是變量的引用綁定;koa
二、任何未顯式導出的變量、函數或類都是模塊私有的,沒法從模塊外部訪問;模塊化
// es6_a.mjs export let aNum = 1; export let aArr = [1]; setTimeout(() => { aNum = 11; aArr.push(11); console.log('1s a模塊改變數據aNum&aArr:'); console.log(`aNum=${aNum},`); console.log(`aArr=${aArr},`); }, 1000) console.log(`a模塊已導出數據:aNum=${aNum},aArr=${aArr}`); // es6_b.mjs // import時必須加{ } import {aNum, aArr} from './es6_a.mjs'; console.log(`b模塊已接收數據:aNum=${aNum},aArr=${aArr}`); setTimeout(() => { console.log(`2s b模塊接受數據:aNum=${aNum},aArr=${aArr}`); }, 2000); // 輸出結果 a模塊已導出數據:aNum=1,aArr=1 b模塊已接收數據:aNum=1,aArr=1 1s a模塊改變數據aNum&aArr: aNum=11 aArr=1,11 2s b模塊接受數據:aNum=11,aArr=1,11
二、export default
有點特殊,導出的數據要根據數據類型來定,與CommonJS的module.exports
有點相似函數
// es6_a.mjs let aNum = 1; let aArr = [1]; setTimeout(() => { aNum = 11; aArr.push(11); console.log('1s a模塊改變數據aNum&aArr:'); console.log(`aNum=${aNum}`); console.log(`aArr=${aArr}`); }, 1000) // 與module.exports相似 export default { aNum, // 數值類型 深拷貝 aArr // 對象類型 淺拷貝 } console.log(`a模塊已導出數據:aNum=${aNum},aArr=${aArr}`); // es6_b.mjs import a from './es6_a.mjs'; console.log(`b模塊已接收數據:aNum=${a.aNum},aArr=${a.aArr}`); setTimeout(() => { console.log(`2s b模塊接受數據:aNum=${a.aNum},aArr=${a.aArr}`); }, 2000); // 輸出結果 a模塊已導出數據:aNum=1,aArr=1 b模塊已接收數據:aNum=1,aArr=1 1s a模塊改變數據aNum&aArr: aNum=11 aArr=1,11 2s b模塊接受數據:aNum=1,aArr=1,11
三、* 在export * from 'xxx'
後面加註釋會報怪異的bug,導出的數據爲undefined
一、導入default
的不須要使用{ }
,導入非默認模塊則須要加{ }
二、一個文件能夠同時導出默認的模塊和非默認的模塊,以下所示:
// es6_a.mjs export let color = 'red'; export default function(num1, num2) { return num1 + num2; } // es6_b.mjs // 默認值必須排在非默認值以前 import sum, { color } from './es6_a.mjs'; console.log(sum(1,2)); console.log(color); // 輸出結果 3 red
三、可使用as
在導出和導入時重命名
// es6_a.mjs function sum(num1, num2) { return num1 + num2; } export { sum as a }; // es6_b.mjs import { a as aa } from './es6_a.mjs'; console.log(aa(1,2)); // 輸出結果 3
1. CommonJS 模塊輸出的是一個值的拷貝(根據數據類型分爲深拷貝或淺拷貝),ES6 模塊輸出的是值的引用(任何數據類型)
CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。ES6 模塊的運行機制與 CommonJS 不同。JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊裏面去取值。換句話說,ES6 的import有點像 Unix 系統的「符號鏈接」,原始值變了,import加載的值也會跟着變。所以,ES6 模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
2. CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口
3. ES6 Module中導入的數據爲const
,不容許從新賦值;而CommonJS中導入的數據容許從新賦值