1、原始写法
function m1(){
//...
}
function m2(){
//...
}
这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。
2、对象写法
var module1 = new Object({
_count : 0,
m1 : function (){
//...
},
m2 : function (){
//...
}
});
上面的函数都封装在module
里可通过module1.m1();
访问,但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写module1._count = 5;
3、立即执行函数写法
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
这样写外部代码无法读取内部的_count变量。
这种写法就是Javascript模块的基本写法。下面,再对这种写法进行加工。
4、放大模式
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。
var module1 = (function (mod){
mod.m3 = function () {
//...
};
return mod;
})(module1);
上面的代码为module1模块添加了一个新方法m3(),然后返回新的module1模块。
5、宽放大模式(Loose augmentation)
在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
var module1 = ( function (mod){
//...
return mod;
})(window.module1 || {});
输入全局变量
var module1 = (function ($, YAHOO) {
//...
})(jQuery, YAHOO);
6、模块化规范
1、CommonJS规范(同步加载模块)主要用于服务端
// 导入
require("module");
require("../app.js");
// 导出
exports.getStoreInfo = function() {};
module.exports = someValue;
- 优点:
简单容易使用
服务器端模块便于复用 - 缺点:
同步加载方式不适合在浏览器环境中使用,同步意味着阻塞加载,浏览器资源是异步加载的
不能非阻塞的并行加载多个模块
参照CommonJs模块代表node.js的模块系统
2、AMD(异步加载模块)
// 定义
define("module", ["dep1", "dep2"], function(d1, d2) {...});
// 加载模块
require(["module", "../app"], function(module, app) {...});
- 优点:
适合在浏览器环境中异步加载模块
可以并行加载多个模块 - 缺点:
提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
不符合通用的模块化思维方式,是一种妥协的实现
实现AMD规范代表require.js
3、CMD规范(异步加载模块)
define(function(require, exports, module) {
var a = require('./a');
a.doSomething();
// 依赖就近书写,什么时候用到什么时候引入
var b = require('./b');
b.doSomething();
});
- 优点:
依赖就近,延迟执行
可以很容易在 Node.js 中运行 - 缺点:
依赖 SPM 打包,模块的加载逻辑偏重
实现代表库sea.js:SeaJS对模块的态度是懒执行, SeaJS只会在真正需要使用(依赖)模块时才执行该模块
AMD 与 CMD 的区别:
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从2.0开始,也改成了可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
- AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require。
UMD - UMD是AMD和CommonJS的糅合
- AMD 以浏览器第一原则发展异步加载模块。
- CommonJS 模块以服务器第一原则发展,选择同步加载,它的模块无需包装。
- UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式;在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。
ES6模块化
- ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
- ES6 模块设计思想:尽量的静态化、使得编译时就能确定模块的依赖关系,以及输入和输出的变量(CommonJS和AMD模块,都只能在运行时确定这些东西)。
使用方式:
// 导入
import "/app";
import React from “react”;
import { Component } from “react”;
// 导出
export function multiply() {...};
export var year = 2018;
export default ...
...
- 优点:
容易进行静态分析
面向未来的 EcmaScript 标准 - 缺点:
原生浏览器端还没有实现该标准
全新的命令字,新版的 Node.js才支持。
https://segmentfault.com/a/1190000015991869#articleHeader8
https://zhuanlan.zhihu.com/p/26231889