在初学闭包时,对于模块这个概念太过模糊,也不了解,今天花了点时间去弄懂它!!!
模块的定义
在讲之前,我们先看一段代码
function CoolMudules() {
var something = 'cool';
var another = [1,2,3];
function doSomething(){
console.log(something);
}
function doAnother () {
console.log(another.join("1"))
}
return{
doSomething:doSomething,
doAnother:doAnother
};
}
var foo = CoolMudules();
foo.doSomething();//cool
foo.doAnother();//1!2!3
这个模式在JavaScript中称为模块。我们最常见的实现模块模式的方法通常被称为模块暴露。在这段代码中,CoolModules()返回一个用对象字面量语法来表示的对象。我们可以将这个对象类型的返回值看做本质上模块API。dosomething()和doAnother()函数具有涵盖模块示例内部作用域的闭包。当通过返回一个含有属性应用的对象的方式来讲函数传递到词法作用域外部时,我们就已经创造了可以观察和实践的闭包的条件。
模块模式必备的两个必要条件:
- 必须有外部的封闭函数,该函数必须至少被调用一次;
- 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态;
总的来说就是,它是一个具有函数属性的对象,而且还要是有闭包函数的对象才行。
模块也是普通的函数,也可以接收参数:
function CoolModule(id) {
function identify() {
console.log(id);
}
return {
identify:identify
};
}
var foo1 = CoolModule('xs');
var foo2 = CoolModule('xr');
foo1.identify();//xs
foo2.identify();//xr
模块模式另一个简单但强大的用法就是命名将要作为公共API返回的对象
var xx = (function Cool(id) {
function change(){
//修改公共API
publicAPI.idNum = idNum2;
}
function idNum1() {
console.log(id);
}
function idNum2() {
console.log(id.toUpperCase());
}
var publicAPI = {
change:change,
idNum :idNum1
};
return publicAPI;
})('xs');
xx.idNum();//xs
xx.change();
xx.idNum();//XS
现代的模块机制
大多数模块依赖加载器。管理器本质上都是将这种模块定义封装进一个友好的API。
下面这段代码它符合前面列出的模块模式的两个特点;强调了包装函数定义的包装函数,并且将返回值作用该模块的API。换句话说,模块就是模块,即使在它们外层加上一个友好的包装工具也不会发生任何变化
var MyModules = (function Manage(){
var modules = {};//保存了所有定义的模块的模块池
/*
name:模块的名字
deps:该模块依赖的其他模块,数组的形式出现
impl:模块的定义,即该模块所包含的方法
*/
function define(name, deps, impl){
//遍历deps里面所有的模块,从模块池中取出
for(var i =0; i < deps.length; i++){
deps[i]=modules[deps[i]];
}
//将新模块存储进模块池,并注入依赖
modules[name] = impl.apply(impl,deps);
}
//从模块池中取出模块
function get(name){
return modules[name];
}
return {
define:define,
get:get
};
})();
MyModules.define('bar',[],function () {
function hello(who) {
return 'let me introduce:' + who;
}
return {
hello:hello
};
});
MyModules.define('foo',['bar'],function (bar) {
var hungry = 'hippo';
function awesome(){
console.log(bar.hello(hungry).toUpperCase());
}
return {
awesome:awesome
};
});
//将foo模块存储进模块池中并注入依赖(将foo模块方法的this指向bar模块,所以可以调用bar模块中的hello方法)
var bar = MyModules.get('bar');
var foo = MyModules.get('foo');
console.log(bar.hello('hippo'));//let me introduce:hippo
foo.awesome();//LET ME INTRODUCE:HIPPO
```