ES6模塊和CommonJS模塊

NO IMAGE

具體的兩大差異如下

  • CommonJS模塊輸出的是一個值的複製,ES6模塊輸出的是值的引用
  • CommonJS模塊是運行時加載,ES6模塊是編譯時輸出接口

第一個差異的原因:

CommonJS模塊輸出的是值的複製,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。(模塊可以多次加載,但是隻會在第一次加載時運行一次,然後運行結果就被緩存了,以後再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。)

//lib.js
var counter = 3
function incCounter() {
counter++
}
module.exports = {
counter: counter,
incCounter: incCounter
}
//main.js
var mod = require('./lib')
console.log(mod.counter)    //3
mod.incCounter()
console.log(mod.counter)    //3

ES6模塊的運行機制與CommonJS不一樣。JS引擎對腳本靜態分析的時候,遇到模塊加載命令import就會生成一個只讀引用。等到腳本真正執行的時候,再根據這個只讀引用到被加載的模塊中取值

//lib.js
export let counter = 3
export function incCounter() {
counter++
}
//main.js
import { counter, incCounter } from './lib.js'
console.log(counter)    //3
incCounter()
console.log(counter)    //4

所以,ES6模塊不會緩存結果,而是動態的去被加載的模塊取值,並且變量總是綁定其所在的模塊。

由於ES6輸入的模塊變量只是一個“符號連接”,所以這個變量是隻讀的,對它進行重新賦值會報錯。

ES6模塊中,頂層的this指向undifined, CommonJS模塊的頂層this指向當前模塊

tips: 提一下commonJS模塊加載的原理

CommonJS的一個模塊就是一個腳本文件。require命令第一次加載該腳本時就會執行整個腳本,然後在內存中生成一個對象。

Module {
id: '...',
exports: { ... },
loaded: true,
...
}

ES6模塊和CommonJS模塊

其中loaded表示該模塊的腳本是否執行完畢。以後需要用到這個模塊時就回到exports屬性上面取值。即使再次執行require命令,也不會再次執行該模塊,而是到緩存中取值。

從代碼和圖中可以看到,module.exports和exports指向的同一塊內存空間,而當直接給module.exports或exports賦值時,就相當於改變了內存,兩者指代的就不是同一內存,這樣就會導致exports中的內容失效,因為module.exports所指向的內存永遠是真正的內存

ES6模塊和CommonJS模塊

有一種賦值特殊就是,exports = module.exports 這個用來重新建立引用關係的

就是重新把無效內存指向真正內存 這樣 exports 和 module.exports 就重新建立了聯繫

相關文章

【譯】Async/await和Promise的不為人知的祕密

Promise源碼

手寫new

手寫call、apply、bind