iT邦幫忙

2021 iThome 鐵人賽

DAY 7
1
Modern Web

JavaScript Easy Go!系列 第 7

#7 JavaScript Modules

今天來介紹 JavaScript 的模組 esm 系統及 commonjs 系統。

什麼是模組

當我們的程式越寫越複雜時,不再適合把幾千行的程式碼全部放在同一個檔案內,這樣不僅難以更新維護,發生錯誤時也難以及時發現處理。

所以我們會將程式碼拆成一塊一塊,把相似功能的程式碼放到一個一個檔案中,再一層一層的引用。這樣不僅維護相對容易,在做部分項目更新時也較為方便,避免誤觸不相干的程式碼外,在思考時也較能專注在相關程式碼上。

這樣拆成一個一個的檔案,再用引用的方式使用,我們就可將之稱為模組。

JavaScript 的模組設計

最早 JavaScript 是沒有模組設計的,因為通常都是被 HTML 一個個 <script> 引入使用。

也因此當時爲 JavaScript 設計模組的責任就落到了開發者身上,所以出現許多不同的第三方模組系統,其中較為知名的應該是 commonjsumdamd 了。

後來又經過了幾年,在 2015 年時隨著 ES6 的正式發布,JavaScript 終於迎來了標準版本的模組系統,稱為 esm

隨著時間的流逝,也因為標準模組系統 esm 的出現,許多第三方模組系統就慢慢被遺棄了。不過,也不是全部的第三方模組系統都被 esm 取代了,像是因為 Node.js 預設使用的模組系統是 commonjs,所以其生態仍是非常豐富,開發者社群也相當活躍。而 umd 因為可以直接使用,不需要額外的引用方式,在 <script> 可以直接引用的特性,也還是有一定的可見性。

所以接下來會對 esmcommonjs 做較為詳細的解說。

ESM

esm 作為標準的模組系統,其重要性近年來持續上升,對其的支援也越趨廣泛。

export & import

esm 用了非常好懂的 exportimport 關鍵字來定義模組的匯出物件,以及引用時使用的物件。

常見的 export 方式:

// mod.js
const cool_things = {
    c1: "我是常數",
    f1() {},
    f2() {},
};

export default cool_things;
// or
export { ...cool_things };

兩種 export 的差異在於 import 時的可用性。
export default,可以用任意名稱 import,而另一個方法則否。

// 使用 export default 時的 import 方法
// 兩者會引入相同東西至不同名稱物件中
import things from "./mod.js";
import something from "./mod.js";

// 使用 export { ... } 時的 import 方法
// 可以選擇引入其中數項,不需全部引入
import { c1, f2 } from "./mod.js"; // 只引入 c1 及 f2

需要注意的是,import 會在一開始時就引入,且會等所有模組皆被引入後再執行其餘程式。

import()

因為 import 的優先引入可能會引入不必要的模組或阻擋主程式的運行,所以 esm 中還有一種動態引用的方法 import(),其會回傳一個 Promise 包著的 module。

(async () => {
    doSomethingWithoutModule();
    const mod = await import("./mod.js");
    mod.doSomething();
})();

在 <script> 中引用

記得要加上 type="module" attribute 才能使用。

CommonJS

CommonJS 作為 Node.js 長久以來使用的模組系統,當然在使用 Node.js 時會用到啦。

require

require 是 CommonJS 用來引入模組的函式。

const mod = require("./mod.js");
// 或是只引入部分
const { c1, f2 } = require("./mod.js");

require 可以在任何地方使用,不一定要在檔案最上面引用,可以依判斷條件動態引用不同模組等。

exports & module.exports

exportsmodule.exports 則是用來匯出模組物件的。

exports 其實就是 module.exports,就好像是系統已經幫你寫好了 var exports = module.exports; 一樣。

const cool_things = {
    c1: "我是常數",
    f1() {},
    f2() {},
};

// 匯出 cool_things
module.exports = cool_things;

// 或分項匯出
exports.c1 = cool_things.c1;
exports.f1 = cool_things.f1;
exports.f2 = cool_things.f2;
exports.c2 = "我是另一個常數";

其實 exports 物件就可以想成是這個模組對外的介面。


每日鐵人賽熱門 Top 10 (0920)

以 9/20 12:00 ~ 9/21 12:00 文章觀看數增加值排名

  1. +321 深入淺出 Computed
    • 作者: Chris
    • 系列:Vue.js 進階心法
  2. +246 Day 2:什麼是 SRE
    • 作者: bogay
    • 系列:這個 site 就是遜啦 - SRE 30 天登大人之旅
  3. +210 #1 JavaScript Easy Go!
    • 作者: JacobLinCool
    • 系列:JavaScript Easy Go!
  4. +205 LeetCode 是什麼?為什麼要刷題?
    • 作者: WeiYuan
    • 系列:LeetCode 雙刀流:Python x JavaScript
  5. +204 LeetCode 解題的思考策略與解題地圖
    • 作者: WeiYuan
    • 系列:LeetCode 雙刀流:Python x JavaScript
  6. +201 Day 1 無限手套 AWS 版:掌控一切的 5 + 1 雲端必學主題
    • 作者: 用圖片高效學程式
    • 系列:無限手套 AWS 版:掌控一切的 5 + 1 雲端必學主題
  7. +199 [Day 02] 什麼是tinyML?
    • 作者: 史蒂芬周
    • 系列:爭什麼,把AI和MCU摻在一起做tinyML就對了!
  8. +199 [Day 02] 什麼是tinyML?
    • 作者: 史蒂芬周
    • 系列:爭什麼,把AI和MCU摻在一起做tinyML就對了!
  9. +194 #4 Array & Object in JavaScript
    • 作者: JacobLinCool
    • 系列:JavaScript Easy Go!
  10. +181 Proxmox VE 安裝虛擬機:Windows 10 (一)
    • 作者: Jason Cheng (節省哥)
    • 系列:突破困境:企業開源虛擬化管理平台

AWS 稱霸 2 天後就幾乎全部消失了
說到 LeetCode,讓我想起了 LeetCode Stats Card


上一篇
#6 JavaScript & Node.js
下一篇
#8 Web Crawler 1
系列文
JavaScript Easy Go!31

尚未有邦友留言

立即登入留言