导航
立即执行函数执行完后作用域销毁,自身的 AO,GO 都销毁,只剩下 return 返回值和返回值持有的函数中的变量的引用(e.g. 闭包) 做到了变量的私有化
var module = (function(moduleA) { // 把参数缓存为私有变量
const obj = {
m1,
m2
}
return {
obj
})(window.moduleA || {}); // 👈 实现模块注入,模块参数一目了然
无模块化 → CommonJS规范 → AMD规范 → CMD规范 → ES6模块化
<script src="jquery.js"></script>
<script src="jquery_scroller.js"></script>
<script src="main.js"></script>
...
缺点:
被依赖的放在前面,否则使用就会报错
污染全局作用域
维护成本高
依赖关系不明显
// 定义模块math.js
var basicNum = 0;
function add(a, b) {
return a + b;
}
module.exports = { //在这里写上需要向外暴露的函数、变量
add: add,
basicNum: basicNum
}
// 引用自定义的模块时,参数包含路径,可省略.js
var math = require('./math');
math.add(2, 5);
// 引用核心模块时,不需要带路径
var http = require('http');
http.createService(...).listen(3000);
exports 是对 module.exports 的引用。比如我们可以认为在一个模块的顶部有这句代码: exports = module.exports
所以,我们不能直接给 exports 赋值:
✅ exports.foo = 'bar'
❌ exports = {foo: 'bar'} //error 这种方式是错误的,相当于重新定义了exports
解决了依赖、全局变量污染的问题
CommonJS 用同步的方式加载模块,这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。所以不适合浏览器端模块加载,更合理的方案是使用异步加载。
AMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
/** 网页中引入require.js及main.js **/
<script src="js/require.js" data-main="js/main"></script>
/** main.js 入口文件/主模块 **/
// 首先用config()指定各模块路径和引用名
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min", //实际路径为js/lib/jquery.min.js
"underscore": "underscore.min",
}
});
// 执行基本操作
require(["jquery","underscore"],function($,_){
// some code here
});
适合在浏览器环境中异步加载模块、并行加载多个模块
必须要提前加载所有的依赖,然后才可以使用,而不是需要使用时再加载。(不能按需加载)
与AMD类似。
不同点在于:
/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {
// 等于在最前面声明并初始化了要用到的所有模块
a.doSomething();
if (false) {
// 即便没用到某个模块 b,但 b 还是提前执行了
b.doSomething()
}
});
/** CMD写法 **/
define(function(require, exports, module) {
var a = require('./a'); //在需要时声明
a.doSomething();
if (false) {
var b = require('./b');
b.doSomething();
}
});
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
return a + b;
};
export { basicNum, add };
/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
ele.textContent = add(99 + basicNum);
}
es6 在导出的时候有一个默认导出 export default
,使用它导出后,在 import 的时候,不需要加上 {} ,模块名字可以随意起。该名字实际上就是个对象,包含导出模块里面的函数或者变量。
/** export default **/
//定义输出
export default { basicNum, add };
//引入
import math from './math';
function test(ele) {
ele.textContent = math.add(99 + math.basicNum);
}
立即执行函数,不暴露私有成员
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();