背景:
一个网站由很多页面组成,以前开发人员习惯以页面的维度将开发任务或者代码分割开来,这也算是模块化的开发。但是一个页面往往也比较复杂,所有的js代码或者HTML代码写在一起很难维护,所以出现了更为完善的前端模块话开发方法,目的就是让代码更容易管理,可以提高代码的复用率。
通常来说,一个文件就是一个模块,有自己的作用域,只需要向外暴露特定的函数或变量。
常见的JS模块化规范
- CommonJS
- AMD
- CMD
- ES6模块系统
1.CommonJS
在node.js中主要使用CommonJS规范来进行模块化的实现,主要提供了module、exports、require、groble几个环境变量来实现模块化。
代码示例:
// add.js
function add(a, b) {
console.log(a + b);
}
module.exports = { // 将方法暴露出去
add,
};
// index.js
const addModule = require("./add"); // 引入add模块
addModule.add(1, 2); // 调用模块中的方法
commonjs采用同步的方式加载模块,在服务端,这种方式不会出现问题,因为模块文件都存在本地,读取速度很快,但是如果在网页端使用commonjs方式进行模块化,由于网络的原因,就可能出现问题,所以nodejs才是commonjs的最佳实践。
2.AMD
AMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。使用AMD规范时,通常需要使用require.js来进行异步加载模块,用require.config()
指定引用路径等,用define()
定义模块,用require()
加载模块。
代码示例:
// 引入require.js
<script src="js/require.js"></script> // 下载require.js后然后引入
// 首先用config()指定各模块路径和引用名,所有的模块都会以这个基础路径作为参考
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min", //实际路径为js/lib/jquery.min.js
"underscore": "underscore.min",
}
})
// 定义模块
define("模块名称", ["模块的依赖项"], function(){
函数体:模块的具体实现,模块中所有的代码全都放在该函数中
})
// 引用模块
require(["模块文件的路径(不带.js后缀的)"], function(){
模块加载成功之后的回调函数
模块的加载是异步的,在模块加载完成之后,才能使用模块的相关功能
})
3.CMD
CMD是另一种js模块化方案,它与AMD很类似,不同点在于:AMD 推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行。CMD主要使用的时seajs来进行的模块化管理。
代码示例**:**
// 定义模块 math.js
define(function(require, exports, module) {
var $ = require('jquery.js');
var add = function(a,b){
return a+b;
}
exports.add = add;
});
// 加载模块
seajs.use(['math.js'], function(math){
var sum = math.add(1+2);
});
4.ES6 Module
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
代码示例:
/** 定义模块 math.js **/
let add = function (a, b) {
return a + b;
};
export { add };
/** 引用模块 **/
import { add } from './math';
console.log(add(99 + 100))
5.ES6模块与CommonJS模块的区别
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。