Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >前端模块化规范

前端模块化规范

原创
作者头像
HZFEStudio
修改于 2021-09-14 02:30:26
修改于 2021-09-14 02:30:26
7770
举报
文章被收录于专栏:HZFEStudioHZFEStudio

完整高频题库仓库地址:https://github.com/hzfe/awesome-interview

完整高频题库阅读地址:https://hzfe.github.io/awesome-interview/

相关问题

  • JavaScript 主要有哪几种模块化规范
  • AMD / CMD 有什么异同
  • ESM 是什么
  • 模块化解决了什么问题/痛点

回答关键点

CommonJS AMD CMD UMD ESM

  • CommonJS<sup>1</sup>: 主要是 Node.js 使用,通过 require 同步加载模块,exports 导出内容。
  • AMD<sup>2</sup>: 主要是浏览器端使用,通过 define 定义模块和依赖,require 异步加载模块,推崇依赖前置
  • CMD<sup>3</sup>: 和 AMD 比较类似,主要是浏览器端使用,通过 require 异步加载模块,exports 导出内容,推崇依赖就近
  • UMD<sup>4</sup>: 通用模块规范,是 CommonJS、AMD 两个规范的大融合,是跨平台的解决方案。
  • ESM<sup>5</sup>: 官方模块化规范,现代浏览器原生支持,通过 import 异步加载模块,export 导出内容。

知识点深入

1. 为什么需要模块化和模块化规范

模块化可以解决代码之间的变量、函数、对象等命名的冲突/污染问题,良好的模块化设计可以降低代码之间的耦合关系,提高代码的可维护性、可扩展性以及复用性。

模块化规范的作用是为了规范 JavaScript 模块的定义和加载机制,以统一的方式导出和加载模块,降低学习使用成本,提高开发效率。

2. 各种模块化规范的细节

2.1 CommonJS

CommonJS 主要是 Node.js 使用,通过 require 同步加载模块,exports 导出内容。在 CommonJS 规范下,每一个 JS 文件都是独立的模块,每个模块都有独立的作用域,模块里的本地变量都是私有的。

示例

代码语言:txt
AI代码解释
复制
// hzfe.js
const hzfeMember = 17;
const getHZFEMember = () => {
  return `HZFE Member: ${hzfeMember}`;
};
module.exports.getHZFEMember = getHZFEMember;

// index.js
const hzfe = require("./hzfe.js");
console.log(hzfe.getHZFEMember()); // HZFE Member: 17

使用场景

CommonJS 主要在服务端(如:Node.js)使用,也可通过打包工具打包之后在浏览器端使用。

加载方式

CommonJS 通过同步的方式加载模块,首次加载会缓存结果,后续加载则是直接读取缓存结果。

优缺点

优点

  • 简单易用
  • 可以在任意位置 require 模块
  • 支持循环依赖

缺点

  • 同步的加载方式不适用于浏览器端
  • 浏览器端使用需要打包
  • 难以支持模块静态分析
2.2 AMD (Asynchronous Module Definition)

AMD,即异步模块定义。AMD 定义了一套 JavaScript 模块依赖异步加载标准,用来解决浏览器端模块加载的问题。AMD 主要是浏览器端使用,通过 define 定义模块和依赖,require 异步加载模块,推崇依赖前置

AMD 模块通过 define 函数定义在闭包中:

代码语言:txt
AI代码解释
复制
/**
 * define
 * @param id 模块名
 * @param dependencies 依赖列表
 * @param factory 模块的具体内容/具体实现
 */
define(id?: string, dependencies?: string[], factory: Function | Object);

示例

代码语言:txt
AI代码解释
复制
// hzfe.js
define("hzfe", [], function () {
  const hzfeMember = 17;
  const getHZFEMember = () => {
    return `HZFE Member: ${hzfeMember}`;
  };

  return {
    getHZFEMember,
  };
});

// index.js
require(["hzfe"], function (hzfe) {
  // 依赖前置
  console.log(hzfe.getHZFEMember()); // HZFE Member: 17
});

使用场景

AMD 主要在浏览器端中使用,通过符合 AMD 标准的 JavaScript 库(如:RequireJs)加载模块。

加载方式

AMD 通过异步的方式加载模块,每加载一个模块实际就是加载对应的 JS 文件。

优缺点

优点

  • 依赖异步加载,更快的启动速度
  • 支持循环依赖
  • 支持插件

缺点

  • 语法相对复杂
  • 依赖加载器
  • 难以支持模块静态分析

具体实现

2.3 CMD (Common Module Definition)

CMD,即通用模块定义。CMD 定义了一套 JavaScript 模块依赖异步加载标准,用来解决浏览器端模块加载的问题。CMD 主要是浏览器端使用,通过 define 定义模块和依赖,require 异步加载模块,推崇依赖就近

CMD 模块通过 define 函数定义在闭包中:

代码语言:txt
AI代码解释
复制
/**
 * define
 * @param id 模块名
 * @param dependencies 依赖列表
 * @param factory 模块的具体内容/具体实现
 */
define(id?: string, dependencies?: string[], factory: Function | Object);

示例

代码语言:txt
AI代码解释
复制
// hzfe.js
define("hzfe", [], function () {
  const hzfeMember = 17;
  const getHZFEMember = () => {
    return `HZFE Member: ${hzfeMember}`;
  };

  exports.getHZFEMember = getHZFEMember;
});

// index.js
define(function (require, exports) {
  const hzfe = require("hzfe"); // 依赖就近
  console.log(hzfe.getHZFEMember()); // HZFE Member: 17
});

使用场景

CMD 主要在浏览器端中使用,通过符合 CMD 标准的 JavaScript 库(如 sea.js)加载模块。

加载方式

CMD 通过异步的方式加载模块,每加载一个模块实际就是加载对应的 JS 文件。

优缺点

优点

  • 依赖异步加载,更快的启动速度
  • 支持循环依赖
  • 依赖就近
  • 与 CommonJS 保持很大的兼容性

缺点

  • 语法相对复杂
  • 依赖加载器
  • 难以支持模块静态分析

具体实现

2.4 UMD (Universal Module Definition)

UMD,即通用模块定义。UMD 主要为了解决 CommonJS 和 AMD 规范下的代码不通用的问题,同时还支持将模块挂载到全局,是跨平台的解决方案。

示例

代码语言:txt
AI代码解释
复制
// hzfe.js
(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    // AMD
    define(["exports", "hzfe"], factory);
  } else if (
    typeof exports === "object" &&
    typeof exports.nodeName !== "string"
  ) {
    // CommonJS
    factory(exports, require("hzfe"));
  } else {
    // Browser globals
    factory((root.commonJsStrict = {}), root.hzfe);
  }
})(typeof self !== "undefined" ? self : this, function (exports, b) {
  const hzfeMember = 17;
  const getHZFEMember = () => {
    return `HZFE Member: ${hzfeMember}`;
  };

  exports.getHZFEMember = getHZFEMember;
});

// index.js
const hzfe = require("./hzfe.js");
console.log(hzfe.getHZFEMember()); // HZFE Member: 17

使用场景

UMD 可同时在服务器端和浏览器端使用。

加载方式

UMD 加载模块的方式取决于所处的环境,Node.js 同步加载,浏览器端异步加载。

优缺点

优点

  • 跨平台兼容

缺点

  • 代码量稍大
2.5 ESM (ECMAScript Module)

ESM,即 ESModule、ECMAScript Module。官方模块化规范,现代浏览器原生支持,通过 import 加载模块,export 导出内容。

示例

代码语言:txt
AI代码解释
复制
// hzfe.js
const hzfeMember = 17;
export const getHZFEMember = () => {
  return `HZFE Member: ${hzfeMember}`;
};

// index.js
import * as hzfe from "./hzfe.js";
console.log(hzfe.getHZFEMember()); // HZFE Member: 17

使用场景

ESM 在支持的浏览器环境下可以直接使用,在不支持的端需要编译/打包后使用。

加载方式

ESM 加载模块的方式同样取决于所处的环境,Node.js 同步加载,浏览器端异步加载。

优缺点

优点

  • 支持同步/异步加载
  • 语法简单
  • 支持模块静态分析
  • 支持循环引用

缺点

  • 兼容性不佳

扩展阅读

1. 静态分析

静态程序分析(Static program analysis)是指在不运行程序的条件下,进行程序分析的方法。 静态程序分析 - Wiki

简而言之,前文里提到的静态分析就是指在运行代码之前就可判断出代码内有哪些代码使用到了,哪些没有使用到。

2. 模块化与工程化:webpack

webpack 同时支持 CommonJS、AMD 和 ESM 三种模块化规范的打包。根据不同规范 webpack 会将模块处理成不同的产物。

CommonJS

代码语言:txt
AI代码解释
复制
(function (module, exports) {
  const hzfeMember = 17;
  const getHZFEMember = () => {
    return `HZFE Member: ${hzfeMember}`;
  };

  module.exports = getHZFEMember;
});

AMD

代码语言:txt
AI代码解释
复制
(function (module, exports, __webpack_require__) {
  var __WEBPACK_AMD_DEFINE_ARRAY__, // 依赖列表
    __WEBPACK_AMD_DEFINE_RESULT__; // factory 返回值

  __WEBPACK_AMD_DEFINE_ARRAY__ = [];

  // 执行 factory
  __WEBPACK_AMD_DEFINE_RESULT__ = function () {
    const hzfeMember = 17;
    const getHZFEMember = () => {
      return `HZFE Member: ${hzfeMember}`;
    };

    return {
      getHZFEMember,
    };
  }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__);

  __WEBPACK_AMD_DEFINE_RESULT__ !== undefined &&
    (module.exports = __WEBPACK_AMD_DEFINE_RESULT__);
});

ESM

代码语言:txt
AI代码解释
复制
(function (module, __webpack_exports__, __webpack_require__) {
  __webpack_require__.r(__webpack_exports__);
  __webpack_require__.d(__webpack_exports__, "getHZFEMember", function () {
    return getHZFEMember;
  });

  const hzfeMember = 17;
  const getHZFEMember = () => {
    return `HZFE Member: ${hzfeMember}`;
  };
});

3. 模块化与工程化:Tree Shaking

Tree shaking 是一个通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)行为的术语。它依赖于 ES2015 中的 import 和 export 语句,用来检测代码模块是否被导出、导入,且被 JavaScript 文件使用。 Tree Shaking - MDN

简单来说,Tree Shaking 是一种依赖 ESM 模块静态分析实现的功能,它可以在编译时安全的移除代码中未使用的部分(webpack 5 对 CommonJS 也进行了支持,在此不详细展开)。

参考资料

  1. Modules: CommonJS modules
  2. Asynchronous module definition
  3. Common Module Definition
  4. Universal Module Definition
  5. Modules: ECMAScript modules
  6. Module Semantics

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JavaScript中的各种模块化规范
前端发展到今天,已经有不少模块化的方案,比如AMD、CMD、UMD、CommonJS等,当然了,还有es6带来的模块系统,这些模块化规范的核心价值都是让 JavaScript 的模块化开发变得简单和自然,今天就来看看这些规范都是啥。 为什么要模块化 在模块化这东西没出来之前,前端脚本引用大概是这样的: <script src="module1.js"></script> <script src="module2.js"></script> <script src="libraryA.js"><
前朝楚水
2018/04/02
8830
js模块化
CMD(common module definition,通用模块定义),它是基于浏览器环境制定的模块规范。
ruochen
2021/12/04
4.6K0
JavaScript——请列出目前主流的 JavaScript 模块化实现的技术有哪些?说出它们的区别?
CommonJS的出发点: JS没有完善的模块系统,标准库较少,缺少包管理工具。伴随着NodeJS的兴起,能让JS在任何地方运行,特别是服务端,也达到了具备开发大型项目的能力,所以CommonJS营运而生。
思索
2024/08/16
2030
Javascript模块化详解
前端的发展日新月异,前端工程的复杂度也不可同日而语。原始的开发方式,随着项目复杂度提高,代码量越来越多,所需加载的文件也越来越多,这个时候就需要考虑如下几个问题:
Clearlove
2021/03/11
6340
Javascript模块化详解
前端模块化
js本身的问题: 不具有模块化的语法规则,在语言层面没有命名空间。 JavaScript 编程过程中很多时候,我们都在修改变量,在一个复杂的项目开发过程中,如何管理函数和变量作用域,显得尤为重要。
前端小tips
2021/12/10
5100
前端模块化
「前端工程四部曲」模块化的前世今生(上)
在日益复杂和多元的Web业务背景下,前端工程化这个概念经常被提及。“说说你对Web工程化的理解?” 相信很多初学者在面试时会经常遇到,而大多数人脑子会直接浮现出 Webpack,认为工程化就是 Webpack 做的那些事情儿,当然也不能说不对,准确说 Webpack 只是工程化背景下产生的工具。
isboyjc
2022/03/28
4690
写给前端新手看的一些模块化知识
一、 为什么需要模块化 以前没有模块化时,我们可能会按如下方式划分模块: 通过 <script> 标签引入各个文件,把每个文件看成是一个模块,每个模块的接口通常是暴露在全局作用域下的,也就是定义在 window 对象中。 <script src="module1.js"></script> <script src="module2.js"></script> <script src="module3.js"></script> 如果通过这种方式做模块化,当项目变得越来越大时,很容易造成全局变量冲突,项目也会
用户1097444
2022/06/29
3330
写给前端新手看的一些模块化知识
如何在JavaScript中实现模块化?
在 JavaScript 中,模块化是一种组织代码的方式,使得代码更加结构化、可维护和可重用。模块化的核心思想是将代码分割成独立的、功能单一的部分(模块),每个模块可以单独处理特定的功能。模块化在大型应用程序开发中特别重要,因为它可以帮助管理复杂性和依赖关系。以下是关于 JavaScript 中模块化的详细讨论,包括不同的模块化方案、它们的优缺点以及如何实现模块化。
王小婷
2025/05/25
800
JS模块化规范总结(面试必备良药)
本文为我之前总结的笔记,因为内容在面试中问得比较多,因而搬运过来,作为面试系列的文章之一。
winty
2019/12/20
1.8K0
一文搞懂 JavaScript 模块化规范:CommonJS、AMD、ES6 Module
在前端开发的历史中,模块化一直是一个核心的问题。随着 JavaScript 应用程序变得越来越复杂,代码的可维护性、复用性和模块化的需求也越来越迫切。
空白诗
2024/09/09
6840
一文搞懂 JavaScript 模块化规范:CommonJS、AMD、ES6 Module
前端模块化-CommonJS,AMD,CMD,ES6
随着 JavaScript 工程越来越大,团队协作不可避免,为了更好地对代码进行管理和测试,模块化的概念逐渐引入前端。模块化可以降低协同开发的成本,减少代码量,同时也是“高内聚,低耦合”的基础。
李振
2021/11/26
4250
前端模块化理解
在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀,这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码。
用户7413032
2020/06/11
6300
前端模块化-总结_前端模块化规范
先说说什么是模块化,就是将独立的功能代码封装成一个独立的文件,其他模块需要使用,在进行引用。
全栈程序员站长
2022/11/17
6670
前端模块化-总结_前端模块化规范
浅析前端模块化
Commonjs是以在浏览器环境外构建JavaScript生态系统为目标而产生的项目,比如在服务器或桌面环境中。
不作声
2021/03/05
2750
前端模块化发展史
相对于其他静态语言,JS最大缺陷就是天生不具有模块化,没有语言层面的命名空间的概念。问题如下:
娜姐
2020/09/22
8870
JavaScript模块化-CommonJS、AMD、CMD、UMD、ES6
AMD(Asynchronous Module Definition)异步模块定义,客户端规范。采用异步方式加载模块,模块加载不影响它后面语句的代执行。
胡哥有话说
2020/04/14
8870
前端模块化开发解决方案详解
AMD(常用在浏览器端,异步的,如requirejs)(Asynchronous Module Definition)
半指温柔乐
2018/09/11
3.8K0
前端模块化开发解决方案详解
【JS】382- JavaScript 模块化方案总结
本文包含两部分,第一部分通过简明的描述介绍什么是 CommonJS、AMD、CMD、UMD、ES Module 以及它们的常见用法,第二部分则根据实际问题指出在正常的 webpack 构建过程中该如何指定打包配置中的模块化参数。
pingan8787
2019/10/18
8580
jQuery源码研究:模块规范兼容
从jq官网down下最新的未压缩版代码并打开后,首先看下整体,这就是一个大型的自执行的匿名函数:
前端_AWhile
2019/08/29
1.1K0
简单的复习下前端模块化相关的知识
作为前端开发,模块化我们已经耳熟能详,我们平时接触到的 ES6 的 import,nodejs中的require他们有啥区别?
前端达人
2022/04/18
4350
相关推荐
JavaScript中的各种模块化规范
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档