Module

​ 當程式碼愈寫愈多,程式的規模愈來愈大時,需要一個管理程式碼的方式,而在 JavaScript 是一個沒有命名空間設計的程式語言,所以早在2003年社群中發展出模組樣式 (module pattern),不過它並沒有辦法徹底解決問題,後來在2009年之後開始發展出兩套真正完整的模組系統,就是 CommonJS 與 RequireJS (Asynchronous Module Definition 簡稱 AMD)。

​ CommonJS 是專門設計給伺服器端的 Node.js 使用,而 AMD 的目標對象則是瀏覽器端,這種方式可以同時間讀取所有引用和相依的模組,不像 CommonJS 所定義的規範是以同步的方式一個一個檔案的載入方式,確保所有相依模組的檔案都載入後才執行,所以 node js 也是採用 CommonJS 這規範。

​ 一個好用的模組系統需包含幾項特點:程式中能載入模組, 模組間的相依性能管理, 異步載入模組, 大型專案一樣好管理。ES6 中加入了模組系統的支援,它採用了 CommonJS 與 AMD 的優點,是一個語言內建的模組系統,並且可以使用於瀏覽器與伺服器端。

CommonJS: require/module.exports

​ CommonJS 是為了解決 JavaScript 作用域問題而定的模組樣式,可以使每個模組自己本身的命名空間中執行。透過  module.exports  匯出對外的變數或函式,當要使用這模組到目前的作用域中,要用  require()  來導入外部模組。

// CommonJS 規範 module 這個字代表當前這個模組
var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
var example = require('./example.js');

console.log(example.x); // 5
console.log(example.addX(1)); // 6

module.exports 屬性表示當前模組對外的接口,實際上也是一個變數

var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();

setTimeout(function() {
  module.exports.emit('ready');
}, 1000);
ES6 的模組系統
  • 不論你在程式碼中有沒有使用 “use strict”, ES6 的模組程式碼會自動變成 strict-mode (嚴格模式)。

  • ES6 的模組是一個檔案一個模組

  • ES6 模組使用 export 與 import 來進行模組輸出與輸入。輸出通常位於檔案最後,輸入位於最前面。

單一輸出名稱
function aFunction(param){
  return param * param
}
// 只會有一個輸出的變數/常數、函式、類別或物件,通常會加上 default
export default aFunction
// 單一輸出的模組就不需要用花括號,這代表只輸入以 default 值定義的輸出語句
import aFunction from './lib2.js'

console.log(aFunction(5))
// 單一輸出的模組,可以直接在輸入時改變輸入值的名稱
import square from './lib2.js'

console.log(square(5))
多個輸出名稱
export const aString = 'test'

export function aFunction(){
  console.log('function test')
}

export const aObject = {a: 1}

export class aClass {
  constructor(name, age){
    this.name = name
    this.age = age
  }
}
// import 方法一,使用大括號,較常使用
import {aString, aObject, aFunction, aClass} from './lib.js'

console.log(aString)
console.log(aObject)
// import 方法二,使用萬用字元 * 並加上一個模組名稱 myModule 防止命名空間的衝突
import * as myModule from './lib.js'

console.log(myModule.aString)
console.log(myModule.aObject)
其他輸入的語法
import 'jquery';                        // import a module without any import bindings
import $ from 'jquery';                 // import the default export of a module
import { $ } from 'jquery';             // import a named export of a module
import { $ as jQuery } from 'jquery';   // import a named export to a different name
import * as crypto from 'crypto';    // import an entire module instance object

Ref

  1. https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/module_system.html
  2. http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281
  3. http://exploringjs.com/es6/ch_modules.html
  4. http://www.2ality.com/2014/09/es6-modules-final.html
  5. https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modularjavascript
  6. https://www.nczonline.net/blog/2016/04/es6-module-loading-more-complicated-than-you-think/