“关注 前端开发社区
,回复"1"
即可加入 前端技术交流群
,回复 "2"
即可免费领取 500G 前端干货!
作者:前端林子 https://cloud.tencent.com/dev…
模块化是指把一个复杂的系统分解到一个一个的模块。
模块化开发的优点:
- (1)代码复用,让我们更方便地进行代码管理、同时也便于后面代码的修改和维护。
- (2)一个单独的文件就是一个模块,是一个单独的作用域,只向外暴露特定的变量和函数。这样可以避免污染全局变量,减少变量命名冲突。
js 模块化规范有:CommonJS
、AMD
、CMD
、ES6
的模块系统。本文将依次介绍下每个规范。
script 引入
`<script type=”text/javascript” src=”a.js”></script>
<script type=”text/javascript” src=”b.js”></script>
<script type=”text/javascript” src=”c.js”></script>
<script type=”text/javascript” src=”d.js”></script>
`
缺点:
- (1)加载的时候会停止渲染网页,引入的 js 文件越多,网页失去响应的时间越长;
- (2)会污染全局变量;
- (3)js 文件之间存在依赖关系,加载是有顺序的,依赖性最大的要放到最后去加载;当项目规模较大时,依赖关系变得错综复杂。
- (4)要引入的 js 文件太多,不美观,代码难以管理。
CommonJS 规范
是服务器端模块的规范,由 nodejs 推广使用。该规范的核心思想是:允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过
exports
或module.exports
来导出需要暴露的接口。
CommonJS
还可以细分为 CommonJS1 和 CommonJS2,区别在于 CommonJS1
只能通过 exports.xx = xx
的方式导出,CommonJS2
在 CommonJS1 的基础上加入了module.exports = xx
的导出方式。CommonJS
通常指 CommonJS2
。
采用 CommonJS 规范导入导出:
`// 导出
module.exports = moduleA.someFunc;
// 导入
const moduleA = require(‘./moduleA’);
`
实例:
`//math.js
var num = 0;
function add(a, b) {
return a + b;
}
module.exports = {
// 需要向外暴露的变量、函数
num: num,
add: add
}
`
可以这样加载:
`// 引入自定义的模块时,参数包含路径,可省略.js
// 引入核心模块时,不需要带路径,如 var http = require(“http”);
var math = require(‘./math’);
math.add(1, 2)//3
`
实际上,从上面的例子就可以看出,math.add(1,2)
必须要等待 math.js
加载完成,即 require
是同步的。
在服务器端,模块文件保存在本地磁盘,等待时间就是磁盘的读取时间。但对于浏览器而言,由于模块都放在服务器端,等待时间取决于网上的快慢。因此更合理的方案是 异步加载模块
。
缺点:
- (1)不能并行加载模块,会阻塞浏览器加载;
- (2)代码无法直接运行在浏览器环境下,必须通过工具转换成标准的 ES5;
2.AMD 和 require.js
AMD:异步模块定义。上面已经介绍过,
CommonJS
是服务器端模块的规范,主要是为了 JS 在后端的表现制定的,不太适合前端。而AMD
就是要为前端 JS 的表现制定规范。由于不是JavaScript
原生支持,使用 AMD 规范进行页面开发需要用到对应的库函数,也就是require.js
(还有个 js 库:curl.js)。实际上 AMD 是require.js
在推广过程中对模块定义的规范化的产出。
AMD
采用 异步
方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
require.js 也采用 require()
语句加载模块,但是不同于 CommonJS:
`// 定义一个模块
define(‘module’, [‘dep’], function (dep) {
return exports;
});
// 导入和使用
require([‘module’], function (module) {
});
`
上面示例中的代码改写成 AMD 形式:
math.js 定义一个模块:
`define(‘math’, [‘jquery’], function (jquery) {// 引入 jQuery 模块
return {
add: function (x, y) {
return x + y;
}
};
});
`
导入和使用:
`require([‘math’], function (math) {
math.add(1, 2)
})
`
math.add()
与加载 math
模块不是同步的,不会阻塞
浏览器的加载。
3.CMD 和 sea.js
CMD:通用模块定义。
国内的玉伯大佬写了 sea.js,实际上 CMD 就是 sea.js 在推广过程中对模块定义的规范化的产出。
`define(function (require, exports, module) {
// 模块代码
});
`
说明:
- require:可以把其他模块导入进来的一个参数;
- exports:可以把模块内的一些属性和方法导出的;
- module:是一个对象,上面存储了与当前模块相关联的一些属性和方法。
上面示例中的代码改写成 AMD 形式:
`define(function (require, exports, module) {
var add = function (a, b) {
return a + b;
}
exports.add = add;
})
// 导入和使用
seajs.use([‘math.js’], function (math) {
var sum = math.add(1, 2);
});
`
CMD 与 AMD 的不同的在于:
- (1)AMD
推崇依赖前置
;CMD推崇依赖就近
,只有在用到某个模块的时候再去 require:
`//AMD 推崇的依赖关系前置:在定义模块时就要声明要依赖的模块
define([‘a’, ‘b’, ‘c’, ‘d’], function (a, b, c, d) {// 依赖必须一开始就写好
a.doSomething()
// 此处省略 100 行
…
b.doSomething()
…
})
//CMD 推崇依赖就近,按需加载,只有在用到某个模块时再去 require
define(function (require, exports, modules) {
var a = require(‘a’);
a.doSomething();
// 此处省略 100 行
…
var b = require(“b”);// 按需加载
b.doSomething();
…
})
`
- (2)AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。
对于依赖的模块,AMD 是 提前执行
,CMD 是 延迟执行
。
具体细节可点击参考
4.ES6 模块化
ES6 在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
在 ES6 中,使用 export
关键字来导出模块,使用 import 关键字引用模块。但是浏览器还没有完全兼容,需要使用 babel 转换成 ES5。
`// 导出
export function hello() {};
export default {
// …
};
// 导入
import {readFile} from ‘fs’;
import React from ‘react’;
`
使用 import 导入模块时,需要知道要加载的 变量名
或函数名
。
在 ES6 中还提供了 export default
,为模块指定默认输出. 对应导入模块import
时,不需要使用 大括号
。
上面示例中的代码改写成 ES6 形式:
`//math.js
var num = 0;
var add = function (a, b) {
return a + b;
};
export {num, add};
// 导入
import {num, add} from ‘./math’;
function test(ele) {
ele.textContent = add(1 + num);
}
`
缺点:
- 浏览器还没有完全兼容,必须通过工具转换成标准的 ES5 后才能正常运行。
小结
本文从 script 引入 js 文件讲起,到服务器端模块的规范 CommonJs
,再到推崇依赖前置的浏览器端模块的规范 AMD、推崇依赖就近的浏览器端模块的规范CMD
,最后介绍了ES6
的模块化。每个介绍中都有各规范基本的用法和一个示例。如有问题,欢迎指正。
最近几天会陆续更新的~~,觉得总结的可以的话,麻烦给小编点一个 在看
, 谢谢!
往期:
JS 基础知识总结(六):只知道 ajax?你已经 out 了
JS 基础知识总结(五):防抖和节流
JS 基础知识总结(四):作用域与闭包
JS 基础知识总结(三):原型、原型链
JS 基础知识总结(二): 浅拷贝与深拷贝
JS 基础知识总结(一)
请各位帅哥美女多多支持帅编,回复 “1”
即可加入前端技术交流群,回复 "2"
即可领取 500G 前端干货