1. 程式人生 > 實用技巧 >區別CommonJS和ES6 Module

區別CommonJS和ES6 Module

區別CommonJS和ES6 Module

1. 靜態和動態

  • 兩者模組規範最本質區別就是,CommonJS對模組依賴的解決是動態的,而ES6 Module對模組的解決是靜態的,舉個例子:
// CommonJS
require(test ? 'a.js' : 'b.js');
// require()的引數可以是變數、表示式,所以不執行程式碼,根本不知道匯入的是哪一個模組,

// ES6 Module
import {a} form './a.js';
// 匯入路徑必須是真實的url字串。所以,在程式碼編譯的時候,就能夠得到到模組之間的依賴關係,進而形成一種靜態的模組結構。
  • 因此,ES6 Module有以下優點:
    • 檢測和排除無用程式碼,減少webpack打包體積
    • 有助於確認模組之間傳遞的值或介面型別是否正確。
    • CommonJs的本質是匯入一個物件,而ES6 Module支援直接匯入一個變數

2. 值拷貝和動態對映

  • CommonJS的匯入,就是值的拷貝,被拷貝到的變數依舊是可以改的
let a = require('a.js').num; 
// 就是把require('a.js').num的值拷貝一份賦值給a而已,a依舊是可以被任意賦值的變數
  • ES6 Module的匯入,是值的對映,並且這個對映只讀
// a.js
export let a = 0;
export let add = ()=>{
	a++;
}
// index.js
import {a, add} from 'a.js';
console.log(a); // 0
add(a); 	// 去到a.js的作用域裡操作a++
console.log(a); // 1
a++; 	        // 報錯,a不可改

總結

  • 瞭解模組,是學習Webpack的必經之路。舉個例子,在webpack裡,對於模組的require,具體程式碼實現如下:
// The require function
function __webpack_require__(moduleId) {
...
	// Check if module is in cache
	if(installedModules[moduleId]) {
		return installedModules[moduleId].exports;
	}
	// Create a new module (and put it into the cache)
	var module = installedModules[moduleId] = {
 		i: moduleId,
 		l: false,
 		exports: {} // 預設匯出值
 	};
...
 	return module.exports;
}
  • 所以,對於CommonJS模組規範,可以這樣理解:
    • 第一次匯入,就會執行一次js程式碼,並把最後的匯出結果記錄到cache裡,第二次再匯入,直接從cache裡提取。這就是為什麼只有第一次require會執行程式碼以及每一次require得到的都是同一個物件的原因
    • CommonJS出現了迴圈依賴的時候(一個被require的js還沒有執行到module.exports,這個時候cache裡面會存在一個它的匯出初始值,然後這個js再次被require的時候),就會直接從cache匯出,匯出的就是預設的匯出值:一個空物件{}
  // foo.js
  let bar = require('./bar.js');
  console.log("value of bar:" + bar);
  module.exports = 'This is foo.js';
  		
  // bar.js
  let foo = require('./foo.js');
  console.log("value of foo:" + foo);
  module.exports = 'This is bar.js';
  		
  // index.js
  require('./foo.js');

  // 輸出結果:
  // value of foo: {}
  // value of bar: This is bar.js