到目前爲止,已經實習了3個月的時間了。最近在面試,在面試題裏面有題目涉及到模塊循環加載的知識。趁着這個機會,將CommonJS模塊與ES6模塊之間一些重要的的區別作個總結。語法上有什麼區別就不具體說了,主要談談引用的區別。html
轉載請註明出處:CommonJS模塊與es6模塊的區別node
上面說了一些重要區別。如今舉一些例子來講明每一點吧es6
// b.js let count = 1 let plusCount = () => { count++ } setTimeout(() => { console.log('b.js-1', count) }, 1000) module.exports = { count, plusCount } // a.js let mod = require('./b.js') console.log('a.js-1', mod.count) mod.plusCount() console.log('a.js-2', mod.count) setTimeout(() => { mod.count = 3 console.log('a.js-3', mod.count) }, 2000) node a.js a.js-1 1 a.js-2 1 b.js-1 2 // 1秒後 a.js-3 3 // 2秒後
以上代碼能夠看出,b模塊export的count變量,是一個複製行爲。在plusCount方法調用以後,a模塊中的count不受影響。同時,能夠在b模塊中更改a模塊中的值。若是但願可以同步代碼,能夠export出去一個getter。面試
// 其餘代碼相同 module.exports = { get count () { return count }, plusCount } node a.js a.js-1 1 a.js-2 1 b.js-1 2 // 1秒後 a.js-3 2 // 2秒後, 因爲沒有定義setter,所以沒法對值進行設置。因此仍是返回2
// b.js let obj = { count: 1 } let plusCount = () => { obj.count++ } setTimeout(() => { console.log('b.js-1', obj.count) }, 1000) setTimeout(() => { console.log('b.js-2', obj.count) }, 3000) module.exports = { obj, plusCount } // a.js var mod = require('./b.js') console.log('a.js-1', mod.obj.count) mod.plusCount() console.log('a.js-2', mod.obj.count) setTimeout(() => { mod.obj.count = 3 console.log('a.js-3', mod.obj.count) }, 2000) node a.js a.js-1 1 a.js-2 2 b.js-1 2 a.js-3 3 b.js-2 3
以上代碼能夠看出,對於對象來講屬於淺拷貝。當執行a模塊時,首先打印obj.count的值爲1,而後經過plusCount方法,再次打印時爲2。接着在a模塊修改count的值爲3,此時在b模塊的值也爲3。緩存
3.當使用require命令加載某個模塊時,就會運行整個模塊的代碼。babel
4.當使用require命令加載同一個模塊時,不會再執行該模塊,而是取到緩存之中的值。也就是說,CommonJS模塊不管加載多少次,都只會在第一次加載時運行一次,之後再加載,就返回第一次運行的結果,除非手動清除系統緩存。dom
5.循環加載時,屬於加載時執行。即腳本代碼在require的時候,就會所有執行。一旦出現某個模塊被"循環加載",就只輸出已經執行的部分,還未執行的部分不會輸出。ui
3, 4, 5可使用同一個例子說明 // b.js exports.done = false let a = require('./a.js') console.log('b.js-1', a.done) exports.done = true console.log('b.js-2', '執行完畢') // a.js exports.done = false let b = require('./b.js') console.log('a.js-1', b.done) exports.done = true console.log('a.js-2', '執行完畢') // c.js let a = require('./a.js') let b = require('./b.js') console.log('c.js-1', '執行完畢', a.done, b.done) node c.js b.js-1 false b.js-2 執行完畢 a.js-1 true a.js-2 執行完畢 c.js-1 執行完畢 true true
仔細說明一下整個過程。code
從以上結果和分析過程能夠看出,當遇到require命令時,會執行對應的模塊代碼。當循環引用時,有可能只輸出某模塊代碼的一部分。當引用同一個模塊時,不會再次加載,而是獲取緩存。htm
// b.js export let counter = { count: 1 } setTimeout(() => { console.log('b.js-1', counter.count) }, 1000) // a.js import { counter } from './b.js' counter = {} console.log('a.js-1', counter) // Syntax Error: "counter" is read-only
雖然不能將counter從新賦值一個新的對象,可是能夠給對象添加屬性和方法。此時不會報錯。這種行爲類型與關鍵字const的用法。
// a.js import { counter } from './b.js' counter.count++ console.log(counter) // 2
// b.js import {foo} from './a.js'; export function bar() { console.log('bar'); if (Math.random() > 0.5) { foo(); } } // a.js import {bar} from './b.js'; export function foo() { console.log('foo'); bar(); console.log('執行完畢'); } foo(); babel-node a.js foo bar 執行完畢 // 執行結果也有多是 foo bar foo bar 執行完畢 執行完畢
因爲在兩個模塊之間都存在引用。所以可以正常執行。
以上以上。對ES6 module和CommonJSmodule有不瞭解的同窗能夠參考一下如下的文章哈