浅谈前端模块化

285 阅读3分钟

背景:

一个网站由很多页面组成,以前开发人员习惯以页面的维度将开发任务或者代码分割开来,这也算是模块化的开发。但是一个页面往往也比较复杂,所有的js代码或者HTML代码写在一起很难维护,所以出现了更为完善的前端模块话开发方法,目的就是让代码更容易管理,可以提高代码的复用率。

通常来说,一个文件就是一个模块,有自己的作用域,只需要向外暴露特定的函数或变量。

常见的JS模块化规范

  1. CommonJS
  2. AMD
  3. CMD
  4. 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 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:exportimportexport命令用于规定模块的对外接口,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模块的区别

  1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。