js模块化
的发展:最早js
是没有模块化概念的,为了防止命名空间被污染
,采用的是命名空间
的方式,随着前端的发展,commonJs
在后端的实践思想被应用在前端,再往后就出现各种模块化标准例如:AMD/CMD/UMD
,到如今出现的新标准es6 module
,js模块化
不断演变,不断由复杂变的更好用。如下简单总结一个各个模块的特点。
1.命名空间(nameSpace)
在没有模块化思想的时候,都是通过命名空间
防止对象被污染,通常格式类似这样库名.类别名.方法名
,如代码所示
var nameSpace = {}
nameSpace.method = nameSpace.method || {}
nameSpace.method.init = function(){
//do somethings
}
nameSpace.method.done = function(){
//do somethings
}
在nameSpace
对象上如果有method
对象就使用nameSpace.method
对象,没有就新建一个空对象用来防止命名冲突或者被覆盖的问题。这种方式的弊端就是如果命名空间被覆盖了,也是没办法检测到的,而且在使用的时候要记住完整的对象方法名,在团队开发的时候大家要提前约定好各自要使用的方法名,类名来避免冲突,很不方便。
2.commonJS
是一种服务端的模块化规范,规定一个文件为一个模块,模块内的变量,方法外界是无法访问的,通过module.exports
暴露模块接口,然后通过require
的方式来引入使用模块接口。commonJs
是运行在nodeJS
服务端的,通过require
进来模块接口都是同步执行的,因为对服务端来说,这种require
方式都是本地加载。
如下代码:
//news.js
const Controller = require('egg').Controller;
class NewsController extends Controller {
async list() {
const dataList = await this.other();
this.ctx.body = {
code:0,
masg:'news list success',
data:dataList
};
}
async other() {
return {
list: [
{ id: 1, title: 'this is news 1', url: '/news/1' },
{ id: 2, title: 'this is news 2', url: '/news/2' }
]
}
}
}
module.exports = NewsController;
3.AMD规范(Async Module Definition 异步的模块定义)
用于浏览器端的js加载,使用define
定义模块,使用require
加载模块,代表库是RequireJS
,这个库的特点就是所有的依赖都会被前置,提前执行,代码格式如下:
define(
//模块名
"alpha",
//依赖模块
["require", "exports", "beta"],
//导出模块
function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
}
);
4.CMD规范(Common Module Definition 通用模块定义)
cmd
也是遵循一个文件为一个模块,也是通过define
来定义模块,通过require
加载模块,代表库是seaJS。
与AMD的区别就是执行方式不一样,CMD是尽可能的懒执行,模块会被下载下来,直到使用的时候才会执行。
代码如下所示:
// 所有模块都通过 define 来定义
define(function(require, exports, module) {
// 通过 require 引入依赖
var $ = require('jquery');
var Spinning = require('./spinning');
// 通过 exports 对外提供接口
exports.doSomething = ...
// 或者通过 module.exports 提供整个接口
module.exports = ...
});
5.UMD(Universal Module Definition )通用解决方案
提供前后端统一的解决方案,实现大一统,支持AMD,CMD两种规范,基本原理就是:判断是否支持AMD,判断是否支持CommonJS,如果都不支持,就定义成全局变量,挂在到window上。
//代码体是个自执行函数
(function (root, factory){
if (typeof define === 'function' && define.amd){
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
//需要被暴露出去的对象eventUtil
root.eventUtil= factory();
}
}(this, function () {
return {};
}));
6.es6 module (EcmaScript Module)
es6 module
也是一个文件就是一个模块,通过export暴露一个接口,通过import引入模块。模块打包现在最好用的就是webpack了。
//定义模块
//requistApi.js
export const getListUrl = 'news/list';
export const getListRequest = (url,params = {}) => {
const promise = new Promise((resolve,reject) => {
$.ajax({
type: "GET",
url: url,
data: params,
dataType: "json",
success: function(data){
resolve(data);
},
error:function(){
reject();
}
});
});
return promise;
}
//引入模块
//list.js
import { getListUrl, getListRequest } from 'requistApi.js'
.....
.....