1) 对象写法
var module1 = new Object({
_count : 0,
m1 : function (){
//...
},
m2 : function (){
//...
}
});
2) 立刻执行函数(Immediately-Invoked Function Expression,IIFE) or 匿名闭包
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
这样可以很好的保护私有变量,通过return来设置公开的方法。缺点也有: 动态添加方法的时候比较麻烦,且无法修改内部私有变量.
3) 放大模式 or 宽放大模式(Loose augmentation)
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用”放大模式”(augmentation)
var module1 = (function (mod){
mod.m3 = function () {
//...
};
return mod;
})(module1);
在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用”宽放大模式”
var module1 = ( function (mod){
//...
return mod;
})(window.module1 || {});
测试
var moduleTest = ( function (mod){
var value1=0, privateName='smt';
function privateAddTopic(data) {
// 这里是内部处理代码
console.log("内部函数");
console.log(data);
}
mod.name = privateName;
mod.init=function(){
this.f1();
this.f3();
};
mod.f1=function(){
console.log("f1--hello");
};
mod.f2=function(){
console.log("f2--hello");
};
mod.f3=function(){
console.log("f3--hello");
};
mod.f4=function(){
console.log("f4--hello");
};
mod.f5=function(data){
privateAddTopic(data);
};
return mod;
})(window.moduleTest || {});
moduleTest.init();
moduleTest.f3();
moduleTest.f5("hello world");
console.log(moduleTest.name);
moduleTest.name = 'zry'; //修改模块中的属性
console.log(moduleTest.name);
现代模块的基本思想实现如下:
var myModules = (function Manager() {
var modules = {}; //定义的模块保存在这个对象里面
function define(name, deps, impl) {//impl是implement的简写,实现的方法
for (var i = 0; i < deps.length; i++) {
deps[i] = modules[deps[i]]; //从保存的对象中获取依赖的模块,注:依赖的模块,肯定已经被define()存放在modules对象中了。
}
modules[name] = impl.apply(impl, deps);//如果此时的模块引入别的模块deps,就将deps作为impl实现的方法的参数
}
/**
* [get 通过名字获得模块]
* @param {[type]} name [模块名]
* @return {[type]} [完整独立模块]
*/
function get(name) {
return modules[name];
}
return {
define: define,
get: get
};
})();
//测试
myModules.define("bar", [], function() {
function hello(who) {
return "hello " + who;
}
return {
hello: hello
};
});
myModules.define("foo", ["bar"], function(bar) {
var n = 'zry';
function awe(who) {
console.log(bar.hello(n).toUpperCase());
}
return {
awe: awe
};
});
var bar = myModules.get("bar");
var foo = myModules.get("foo");
foo.awe();//HELLO ZRY
* 1) CommonJS*
node.js的模块系统,就是参照CommonJS规范实现的
var math = require('math');
math.add(2,3); // 5
第二行math.add(2, 3),在第一行require(‘math’)之后运行,因此必须等math.js加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等。
这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。这就催生AMD规范到来的背景。
* 2) AMD*
AMD(Asynchronous Module Definition)是异步模块加载的意思。
require([module], callback);
require(['math'], function (math) {
math.add(2, 3);
});
主要有两个Javascript库实现了AMD规范:require.js和curl.js
* 3) CMD*
CMD(Custom Module Definition)通用模块加载
引入seajs文件
<script type="text/javascript" src="../../common/jsext/sea-debug.js">script>
seajs 的简单配置
seajs.config({
base: "../sea-modules/",
alias: {
"jquery": "jquery/jquery/1.10.1/jquery.js"
}
})
// 加载入口模块
seajs.use("../static/hello/src/main");//入口
定义模块:
// 所有模块都通过 define 来定义
define(function(require, exports, module) {
// 通过 require 引入依赖
var $ = require('jquery');
var Spinning = require('./spinning');
// 通过 exports 对外提供接口
exports.doSomething = ...
// 或者通过 module.exports 提供整个接口
module.exports = ...
});
另外可以使用seajs-text加载html文件或者tpl片段,seajs-css加载css文件
<script src="path/to/sea.js">script>
<script src="path/to/seajs-text.js">script>
<script>
define("main", function(require) {
// You can require `.tpl` file directly
var tpl = require("./data.tpl")
//或者html
var html =require("./a.html");
$('.some_class').append(html);
})
script>
seajs-css
<script src="path/to/sea.js">script>
<script src="path/to/seajs-css.js">script>
<script>
// seajs can load css file after loading css plugin.
seajs.use("path/to/some.css");
//很多时候可以使用require的方式
require("path/to/some.css");
script>
//bar.js
function hello(who){
return "hello "+who;
}
export {hello};
//foo.js
import {hello} from "bar";
var n = "zry";
function awe(){
console.log(bar.hello(n).toUpperCase());
}
export {awe};
//baz.js
import {bar} from "bar";
import {foo} from "foo";
console.log(bar.hello('smt'));//hello smt
foo.awe();//HELLO ZRY
当然现在需要使用babel转成es5,并且要使用打包工具browserify webpack rollup 等才能直接在现在的浏览器上运行。
参考阅读: