目录
IIFE(Immediately Invoked Function Expression)
AMD(Asynchronous Module Definition)
说明
首先要说明的是,这些模块化的方案已经过时了,只有一些还需要维护的老项目的还在使用,当前基本都是用打包器打包的模块化方案,例如webpack,通过webpack打包之后的方案,就是webpack模块化方式。
IIFE(Immediately Invoked Function Expression)
这是一种原始的方式,能起到的作用仅仅只是隔离模块之间额命令冲突,将各种名字限制在模块内部。模块之间的依赖关系依靠程序员手动解决,通过在html中手动编写script标签来确定依赖关系。
模块定义:
//模块 moduleA.js
(function(window) {
window.jQuery = {
// 这里是代码
};
})(window);
//模块 moduleB.js
(function(window,jQuery) {
window.my_module = {
// 这里是代码
moduleBProerty:jQuery.xxxxx //模块A中定义了全局模块jQuery,这里引用了jQuery,于是moduleB.js依赖moduleA.js
};
})(window,window.jQuery);
//index.html
//moduleB.js依赖moduleA.js,所以先引入moduleA.js
<script src="moudleA.js"></script>
<script src="moudleB.js"></script>
AMD(Asynchronous Module Definition)
文档地址:RequireJS API
AMD规范的实现方式是RequireJS。
AMD (Asynchronous Module Definition)也是一种 JavaScript模块化规范。从名字上可以看出,它主要提供了异步加载的功能。这种方式更加自动化,不需要手动确定依赖关系,使用方式也及其简单。
假设具有如下目录结构的项目:
- www/
- index.html
- js/
- app/
- sub.js
- lib/
- jquery.js
- canvas.js
- app.js
- require.js
- app/
在index.html中:
<script data-main="js/app.js" src="js/require.js"></script>
在app.js中:
requirejs.config({
//By default load any module IDs from js/lib
baseUrl: 'js/lib',
//except, if the module ID starts with "app",
//load it from the js/app directory. paths
//config is relative to the baseUrl, and
//never includes a ".js" extension since
//the paths config could be for a directory.
paths: {
app: '../app'
}
});
// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],
function ($, canvas, sub) {
//jQuery, canvas and the app/sub module are all
//loaded and can be used here now.
});
对于requirejs.config()而言,其参数对象中最重要的两个值就是baseUrl与Paths了,baseUrl定义了这些模块的起始Url地址(如果没有通过requirejs.config配置baseUrl,那么就会取data-main的JS文件所在的目录作为baseUrl;如果没有配置baseUrl或者data-main,则baseUrl默认为index.html的目录路径。),Paths定义了这些模块的相对路径,这个相对路径是相对于baseUrl而言的。
上述引入方式只适合单入口的项目。
将config作为模块引入执行。
在index.html中引入:
<script src="scripts/require.js"></script>
<script>
//在这里,requirejs.config在scripts/config模块中被调用,然后当script/config模块执行完成之后,就会执行这里的回调,从而这里的require得到执行,相关模块被加载。
require(['scripts/config'], function() {
// Configuration loaded now, safe to do other require calls
// that depend on that config.
require(['foo'], function(foo) {
});
});
</script>
定义模块:
定义模块最好采用define(name,callback)与define(callback)这两种形式,而不要采用define(name,deps,callback)这种方式。
具体见:RequireJs运行原理 - axl234 - 博客园 末尾
但是在官方文档中,又建议不要给模块命令,所以就只剩下define(callback)这一种方式了。
目录结构:
* moduleA.js
* moduleB.js
* dir/
* test.js
//文件名:test.js
define(function(require){
//在内部引入依赖模块
var moduleA=require("../moduleA"); //使用moduleA的相对路径即可。
var moduleB=require("../moudleB");
//这里开始写模块代码
return {
test: function(){
moduleA.test();
}
}
});
CMD(Common Module Definition)
CMD(Common Module Definition)最初是由阿里的玉伯提出的,同AMD类似,使用CMD模块也需要使用对应的库SeaJS。SeaJS所要解决的问题和requireJS一样,但是在使用方式和加载时机上有所不同。
CMD的使用:
基本目录:
* CMD/
* index.html
* app.js
* lib/
* moduleA.js
* moduleB.js
定义一个模块:
//定义moduleA模块 moduleA.js
//其中require用于载入其它模块,其中require.async用于懒加载。
//exports用于导出本模块的property
//module有三个properties,比较有用的就是module.exports。
//到处本模块接口的方式有两种弄:
//1. 通过exports一个接口一个接口的导出。exports.xxxxx = xxxxx
//2. 通过module.exports一次性全部到处。module.exports = { xxxxxxx }
define(function(require,exports){
exports.helloA=function(){
console.log("This is moduleA.helloA!");
}
});
//moduleB.js
define(function(require,module){
var moduleA = require("./moduleA");
moduleA.helloA();//调用moduleA中的hello()方法
module.exports = {
helloB:function(){
console.log("This is moduleB!");
}
}
});
定义入口:
// app.js
define(function(require){
var moduleB = require("./lib/moduleB");
moduleB.helloB();
console.log("This is app!");
})
定义html:
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
CMD
</body>
<script src="./static/sea.js"></script>
<script>
seajs.config(
{
base:"./",
alias:{
moduleA:"lib/moduleA.js"
}
}
);
seajs.use("./app.js");
</script>
</html>
CommonJS
node原生支持CommonJS的模块化标准,因此在node中可以直接使用。
//moduleA.js
var add = function(a, b) {
return a + b;
};
module.exports = {
add: add
};
//main.js
var moduleA = require('./moduleA');
console.log(moduleA.add(1, 2));
UMD
UMD(Universal Module Define)其实就是一种兼容各大模块方式的写法。
// moduleA.js
(function(root, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
console.log('是commonjs模块规范,nodejs环境')
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
console.log('是AMD模块规范,如require.js')
define(function(require,exports,module){
module.exports = factory();});
} else if (typeof define === 'function' && define.cmd) {
console.log('是CMD模块规范,如sea.js')
define(function(require, exports, module) {
module.exports = factory()
})
} else {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory(root);
}
}(this, function() {
return {
helloA:function(){console.log("moduleA!")}
}
}));
//main.js
(function(root, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
console.log('是commonjs模块规范,nodejs环境')
var depModule = require('./moduleA.js')
module.exports = factory(depModule);
} else if (typeof define === 'function' && define.amd) {
console.log('是AMD模块规范,如require.js')
define(function(require,exports,module){
var depModule = require('./moduleA');
module.exports = factory(depModule);});
} else if (typeof define === 'function' && define.cmd) {
console.log('是CMD模块规范,如sea.js')
define(function(require, exports, module) {
var depModule = require('./moduleA')
module.exports = factory(depModule)
})
} else {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory(root.depModule);
}
}(this, function(depModule) {
console.log('我调用了依赖模块', depModule)
depModule.helloA();
// ...省略了一些代码,去代码仓库看吧
return {
name: '我自己是一个umd模块'
}
}));
ES6模块
这些例子,我放在Github上:IIFE AMD CMD CommonJS UMD都有。
GitHub - comefromezero/FrontModule: practice for IIFE AMD CMD UMD