#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


<<:  css position

>>:  #06 No-code 之旅 — 用 Next.js 解决前後端?API Routes 简介

Day08:08 - User服务(3) - 後端 - JWT token、修改个人资料

Hej,我是Charlie! 在Day07当中,我们完成了基本的登入跟登出,而在今天我们将完成JWT...

[Day 08] 从 tensorflow.keras 开始的 VGG Net 生活 (第一季)

-1. 序 OK,资料分析做完了, 现在要进入演算法的部分, 我们未来几天将从经典卷积神经网路架构中...

Microsoft Azure Pass 学习日志 Day 4

Chap.IV Data Services 资料库服务 SQL Databases SQL 资料库 ...

Flutter体验 Day 10-表单组件

表单组件 使用表单处理使用者输入是常见的应用的基础功能,使用这些表单组件可以应用在注册、登入、电商…...

Day28 Java 注解

●Java 自定义注解 创建自定义注解类似於编写接口,不同之处在於interface关键字以@符号为...