目录
前言
一、CommonJS 模块化规范
二、ES6 模块化规范
三、AMD 模块化规范
四、CMD 模块化规范
五、UMD模块化规范
前言
这三个规范都是为Js模块化加载而生的,使模块能够按需加载,使系统同庞杂的代码得到组织和管理。模块化的管理代码使多人开发得到了更好的合作。
一、CommonJS 模块化规范
是一种为JS的表现指定的规范,它希望js可以运行在任何地方,更多的说的是服务端模块规范,Node.js采用了这个规范。
CommonJS主要用于服务器端,Node.js是其主要实践者。
核心思想
一个单独文件就是一个模块,通过require方法来同步加载要依赖的模块,然后通过extports或者module.exports来导出需要暴露的接口。
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;
(1) 每一个文件都是一个模块,每一个模块都有一个独立的作用域,文件内的变量,函数都是私有的,其他文件不可使用(除非赋值到 global上)
(2)每个模块内部,module变量代表当前模块
(3)每个文件对外的接口是 module.exports 属性
(4) require用于引用其他模块,实际获得的是其他模块的module.exports这个属性
优点:服务器端模块重用,NPM中模块包多,有将近20万个。
缺点:加载模块是同步的,只有加载完成后才能执行后面的操作,也就是当要用到该模块了,现加载现用,不仅加载速度慢,而且还会导致性能、可用性、调试和跨域访问等问题。Node.js主要用于服务器编程,加载的模块文件一般都存在本地硬盘,加载起来比较快,不用考虑异步加载的方式,因此,CommonJS规范比较适用。然而,这并不适合在浏览器环境,同步意味着阻塞加载,浏览器资源是异步加载的,因此,有了AMD CMD解决方案。
实现:服务器端的 Node.js;Browserify,浏览器端的 CommonJS 实现,可以使用 NPM 的模块,但是编译打包后的 文件体积可能很大;modules-webmake,类似Browserify,还不如 Browserify 灵活;wreq,Browserify 的前身;
小结:commonjs模块化规范
CommonJS规范是同步加载模块,也就是说,在执行到require调用的时候,会立即加载并执行模块。这种同步的方式对服务器端不存在问题,因为所有的模块都在本地,可以直接加载。但是对于浏览器端,模块可能需要通过网络加载,这就需要异步加载,因此,在浏览器端,AMD和CMD规范得到了广泛的应用。
以下是CommonJS规范的一个简单示例:
假设我们有两个文件,一个是math.js
,另一个是main.js
。
math.js:
// math.js
exports.add = function(a, b) {
return a + b;
};
exports.multiply = function(a, b) {
return a * b;
};
main.js:
// main.js
var math = require('./math');
console.log('2 + 3 = ' + math.add(2, 3));
console.log('2 * 3 = ' + math.multiply(2, 3));
在math.js中,我们使用exports对象来暴露模块接口,在main.js中,我们使用require函数来加载math.js模块,并使用其提供的方法。 在Node.js环境中,你可以直接运行这两个文件,因为Node.js采用了CommonJS规范。但是在浏览器环境中,你需要使用像Browserify这样的工具来将CommonJS格式的代码转换成可以在浏览器中运行的格式。
二、ES6 模块化规范
ES6中的Module规范定义了JavaScript的模块。模块功能主要由关键字export
和import
实现。
ES6 模块化适用于浏览器端和服务器端,是JavaScript语言的最新版本,通过
import
和export
语句实现模块化。
export
用于定义模块对外暴露的接口,可以用来导出变量、函数、类等。
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
import
用于从其他模块导入需要的接口。
// app.js
import { add, subtract } from './math.js';
console.log(add(1, 2)); // 输出3
console.log(subtract(10, 5)); // 输出5
模块可以导出单个值,也可以全部导出。
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
export { add, subtract };
// app.js
import * as math from './math.js';
console.log(math.add(1, 2)); // 输出3
console.log(math.subtract(10, 5)); // 输出5
默认导出(default export)只允许每个模块有一个。
// math.js
const add = (a, b) => a + b;
export default add;
// app.js
import math from './math.js';
console.log(math(1, 2)); // 输出3
以上是ES6 Module的基本使用方法。
参考:export default 和 export之间的区别-CSDN博客
三、AMD 模块化规范
鉴于浏览器的特殊情况,又出现了一个规范,这个规范呢可以实现异步加载依赖模块,并且会提前加载,那就是AMD规范。——(Asynchromous Module Definition - 异步模块定义)
AMD主要用于浏览器端,RequireJS是其主要实践者。通过
define()
和require()
函数实现模块化。
其核心接口是:define(id?, dependencies?, factory) ,它要在声明模块的时候指定所有的依赖 dependencies ,并且还要当做形参传到factory 中,对于依赖的模块提前执行,依赖前置。
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ...*/ });
优点:在浏览器环境中异步加载模块;并行加载多个模块;
缺点:开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅;不符合通用的模块化思维方式,是一种妥协的实现;
实现:RequireJS; curl;
小结:AMD规范
AMD规范的定义和基本概念
AMD(Asynchronous Module Definition)是一种异步模块定义规范,主要用于浏览器端的JavaScript模块化。它是由RequireJS的作者James Burke提出的一种模块化规范,旨在解决浏览器环境中多个JavaScript文件依赖关系的问题,并实现异步加载模块。
AMD规范的基本语法
在AMD规范中,每个模块都必须通过define函数定义。define函数可以接收两个到四个参数:第一个参数是模块的名字,第二个参数是一个数组,声明模块的依赖项,第三个参数是一个函数,该函数的参数与前面的依赖项一一对应,用于定义模块的导出成员。例如:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
}
});
AMD规范的使用场景和优缺点
AMD规范适合在浏览器环境中异步加载模块,可以并行加载多个模块并按需加载。RequireJS是实现AMD规范的主要工具,它解决了多个JavaScript文件依赖关系的问题,使得浏览器可以异步加载模块,从而不会阻塞页面的渲染。
优点:
- 适合在浏览器环境中异步加载模块。
- 可以并行加载多个模块。
- 按需加载模块。
缺点:
- 需要第三方库(如RequireJS)支持。
- 模块划分细致时,文件请求频繁。
AMD规范与其他模块化规范的对比
AMD规范与CMD规范和CommonJS规范相比,主要区别在于依赖模块的执行时机和处理方式不同。AMD规范是异步加载模块,而CMD规范是按需加载模块。CommonJS规范适用于服务器端,同步加载模块。
AMD规范通过define
方法定义模块,通过require
方法加载模块,而CMD规范也是通过define
方法定义模块,但执行时机不同。CommonJS规范通过require
命令加载模块,并通过module.exports
或exports
对外暴露接口。
四、CMD 模块化规范
Common Module Definition 规范和 AMD 很相似,尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。——(Common Module Definition - 公共模块定义)
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
优点:依赖就近,延迟执行 可以很容易在 Node.js 中运行;
缺点:依赖 SPM 打包,模块的加载逻辑偏重;
实现:Sea.js ;coolie
小结:CMD规范(Common Module Definition)是一种模块定义规范,它明确了模块的基本书写格式和基本交互规则。 CMD规范专门用于浏览器端,模块的加载是异步的,只有在模块使用时才会加载执行。CMD规范整合了CommonJS
和AMD规范的特点,提供了一个简单且与Modules规范保持较大兼容性的模块化解决方案。
在CMD规范中,一个模块就是一个文件,通过define关键字来定义模块。基本的格式是define(factory);,其中define是一个全局函数,factory可以是函数、对象或字符串。当factory为函数时,它表示模块的构造方法,执行该构造方法可以得到模块向外提供的接口。factory方法在执行时,默认会传入三个参数:require、exports和module。这三个参数分别用于引入其他模块、导出模块的内容以及获取当前模块的信息。
此外,CMD规范推荐一个文件对应一个模块,因此经常使用文件名作为模块的标识。依赖就近的原则也被推荐,即在factory函数中直接写入依赖,而不是在define的参数中指定。这种做法使得代码更加直观和易于维护。
SeaJS是遵循CMD规范的代表库之一,它提供了一个轻量级的模块加载器,使得开发者能够更加方便地使用CMD规范的模块化编程。通过SeaJS,开发者可以更加轻松地实现模块的异步加载和使用,从而提高代码的加载速度和质量。
五、UMD模块化规范
UMD模块化规范是AMD和CommonJS的糅合)。
UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。
在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。
(function (window, factory) {
if (typeof exports === 'object') {
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
define(factory);
} else {
window.eventUtil = factory();
}
})(this, function () {
//module ...
});
总结:
JavaScript的模块化规范主要包括 CommonJS、AMD、CMD、ES6模块化以及UMD。
-
CommonJS:主要应用于服务器端,每个文件都被视为一个模块,通过
require
函数加载模块,使用module.exports
或exports
对象导出模块内容。这种规范适合于Node.js环境,因为它基于服务器端JavaScript的运行环境设计,简单直观,但不适合浏览器环境,因为它采用同步加载方式。 -
AMD (Asynchronous Module Definition):由RequireJS推广,采用异步方式加载模块,支持通过指定回调函数定义依赖模块。这种方式解决了CommonJS在浏览器环境下同步加载的问题,允许模块加载不会阻塞页面的渲染。
-
CMD (Common Module Definition):由SeaJS推广,与AMD类似,但也支持非异步加载。它的使用方式与AMD有所不同,但同样旨在解决模块依赖和异步加载的问题。
-
ES6模块化:ECMAScript 2015引入的原生模块系统,使用
import
和export
关键字实现模块的导入和导出。ES6模块支持静态和动态导入,具有静态解析、异步加载和更好的兼容性等优点,成为现代前端开发中最流行的模块化规范。 -
UMD:是AMD和CommonJS的混合体,旨在同时支持Node.js和浏览器环境。UMD会根据运行环境自动选择使用CommonJS或AMD的模块加载方式。
这些模块化规范各有特点,适用于不同的使用场景。CommonJS适合服务器端开发,而ES6模块化则更适合现代前端开发,提供了更好的异步加载和兼容性。AMD和CMD规范则主要解决了浏览器环境下模块的异步加载问题。UMD则是一种折中的解决方案,旨在同时支持Node.js和浏览器环境。
● 参考资料 ●
AMD规范、CMD规范、CommonJS - 简书 | JavaScript的模块规范有哪些-PHP中文网
JS中的几种模块化规范(CommonJS、AMD、CMD、ES6 Module)-CSDN博客