前言
本篇文章并不会深入原理,更着重表层上每一种模块规范之间的差异的表现。深入的原理以及实现的细节,希望以后有机会可以深入研究。
CommonJS
- 使用
require
和exports
关键字和模块系统进行交互 - CommonJS不支持异步加载
- 一个文件就是一个模块
Nodejs的模块规范受到了CommonJS的影响,但Nodejs支持使用module.exports
导出对象,而CommonJS只使用exports
。CommonJS模块在未经编译前无法使用。示例如下。
// modules/physics.js
module.exports = {
lorentzTransformation () {
},
maxwellSEquations () {
}
}
// index.js
const physics = require('./modules/physics')
physics.lorentzTransformation()
physics.maxwellSEquations()
module.exports 和 exports
module
是一个带有exports
属性的对象,exports
是普通的js变量,是module.exports
的引用。如果设置exports.name = '叶奈法'
,相当于设置module.exports.name = '叶奈法'
。但是,如果给exports
设置了一个新的对象,exports
和module.exports
将不再是同一个对象。
// 简化的理解
var module = { exports: {} }
var exports = module.exports
AMD
AMD诞生的原因是,是因为CommonJS不支持异步加载,不适合浏览器环境。RequireJS实现了AMD API。示例如下。
在index.html
中使用<script/>
标签加载RequireJS,通过data-main
属性指定主文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>AMD</title>
<!-- require.js -->
<script data-main='./index.js' src="./require.js"></script>
</head>
<body>
</body>
</html>
define
关键字用于定义模块,模块分为独立模块(不依赖其他模块的模块)以及非独立模块(依赖其他模块的模块)
// 独立模块
// libs/geometry.js
define(function() {
'use strict';
return {
pythagoreanTheorem(a, b) {
return a * a + b * b
}
}
})
// 非独立模块,本模块引用了geometry模块
// libs/math.js
define(['./geometry.js'], function(geometry) {
'use strict';
return {
geometry: {
pythagoreanTheorem: geometry.pythagoreanTheorem
}
}
})
require
关键字用来引用模块
// index.js
// 加载math模块
require(['./libs/math'], function (math) {
var c = math.geometry.pythagoreanTheorem(1, 2)
alert(c)
})
ES6
ES6在语言层面上实现了模块机制,与CommonJS与AMD规范不同的是ES6的模块是静态的,不能在文件的任何地方使用。这种行为使得编译器编译时就可以构建依赖关系树,但是在ES6模块没法在浏览器中完全实现,需要使用babel,webpack。
// src/modules/physics.js
export function maxwellSEquations () {
alert('maxwellSEquations')
}
// src/main.js
import { maxwellSEquations } from './modules/physics'
maxwellSEquations()
UMD
UMD模块是一种通用的模式,用于兼容AMD和CommonJS的规范。UMD规范同时兼容amd和commonjs,并支持传统的全局变量的模式。
UMD模块的顶端通常都会有如下的代码,用来判断模块加载器环境。
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('jquery'));
} else {
// 全局变量
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// ...
}));