我们已经了解到模块模式是为单例创建私有变量和特权方法的。

一个最基本的例子:

var foo=(function(){
var something='cool',
var another=[1,2,3];
function dosomething(){
console.log(something);
}
function doAnother(){
console.log(another.join('!'));
}
return {
doSomething:doSomething,
doAnother:doAnother
}
})();
foo.doSomething(); //cool
foo.doAnother(); //1!2!3

我们将模块函数转换成了立即执行函数,立即调用这个函数并将返回值直接赋值给单例的模块实例标识符。在函数内部定义了私有变量,并通过函数留下了接口,除了通过接口访问其内部的私有变量的值,在函数外部是无法访问它的值的,这也就保证了不会引起命名冲突,修改数据等问题,同时,模块还可以复用,大大提高了开发效率。

其实,大多数的模块倚赖加载器/管理器本质上都是将这种模块定义封装进一个友好的API(接口)。我们知道,在requirejs中,使用define([],function(){})来定一个模块的,来看下面一段原理性代码。

  var MyModules=(function Manager(){
var moudules={}; //对象字面量
function define(name,deps,impl){
for(var i=0;i<deps.length;i++){
deps[i]=moudules[deps[i]];
}
moudules[name]=impl.apply(impl,deps);
console.log(moudules[name]);
} function get(name){
return moudules[name];
}
return {
define:define,
get:get
};
})();

这里我们定义了一个匿名函数,并让他立即执行,然后将返回值传给了MyModules。

接下来我们执行这样一段代码:

MyModules.define('bar',[],function(){
function hello(who){
return 'Let me introduce:'+who;
}
return {
hello:hello
}
});
var bar=MyModules.get('bar');
console.log(bar.hello('nihao'));

看一下执行结果:

大致分析一下执行过程:

通过MyModules的公共接口define,同时,传给define的第二个参数是一个空数组,所以说,for循环会跳过,这时,最关键的一句是

 impl.apply(impl,deps)

它会将impl也就是第三个匿名函数参数的this值绑定到函数自身的作用域并同时将第二个参数deps作为函数的参数传进去。

这时,modules对象中就多了一个bar属性,其大致的结构跟我们开篇讲的第一个例子,并没有什么两样,我们看一下,其结构:

也就相当于这样:

var bar=function(){
function hello(who){
return 'Let me introduce':+who;
}
return {
hello:hello
}
};

这时,我们再调用get函数获取到其属性,然后调用其hello()方法,结果也就一目了然了。

但这里,我们第二个参数是一个空数组,在requirejs中,也就相当于不倚赖任何模块,那当他需要依赖其他模块时,会是什么样的情况呢,他又是如何完成其他模块的加载的呢?

我们在代码的基础上,继续增加如下代码:

MyModules.define('foo',['bar'],function(bar){
var hungry='hippo';
function awesome(){
console.log(bar.hello(hungry).toUpperCase());
}
return {
awesome:awesome
}
});
var foo=MyModules.get('foo');
foo.awesome();

看一下其执行结果:

是按照我们预想的那样输出的。

我们再来分析一下执行过程:

其关键的步骤就是第二个参数是有一个数组值的数组,代码将执行遍历此数组操作,然后,将该数组的第一个值赋值为此前module对象中的bar属性对象,所以说该数组中的值也就也就指向了moudule对象中的bar属性对象(注意引用类型的复制问题)。

其也就当做参数传递到了modules对象的另外一个属性foo之中,其实,这也就完成了requirejs中加载模块的功能。这时,当我们引用bar模块中的公共接口的时候,其结果也就在情理之中了。

其实,这段代码的核心就是modules[name]=impl.apply(impl,deps)。为了模块的定义引入了包装函数(可以传入任何依赖),并将其返回值,也就是模块的API,存储在一个根据名字来管理的模块列表中。

以上内容,纯属个人理解,如果有不对之处,还请大家热心指正。

最新文章

  1. 洛谷 P1378 油滴扩展 Label:搜索
  2. 不要在控制台上使用 let/const
  3. http://blog.csdn.net/a491057947/article/details/46724707
  4. 用qt代码怎样编写图片保存格式[qt4.6]
  5. Codeforces 389A (最大公约数)
  6. Shell 小技巧
  7. Android 上拉加载更多功能
  8. Apache log4net™ Config Examples
  9. Spring4.0学习笔记(3) —— Spring_Bean之间的关系
  10. codeforces 166C Median - from lanshui_Yang
  11. 两分钟让你明白cocos2dx的屏幕适配策略
  12. vim - manual -个人笔记
  13. Treap详解
  14. centos下安装jenkins
  15. centos 下安装 Jre 及 selenium
  16. 线性素数筛 ACM-ICPC 2018 南京赛区网络预赛 J Sum
  17. 洛谷 P1377 [TJOI2011]树的序 解题报告
  18. git clone错误 fatal: early EOF fatal: index-pack failed
  19. 【LOJ】#2567. 「APIO2016」划艇
  20. 谈谈我的js学习过程(二)&mdash;&mdash;&ldquo;Hello World!&rdquo;

热门文章

  1. windows下npm scripts不能执行的问题
  2. C#动态创建两个按钮,btn2复制btn1的Click事件,匿名委托
  3. 关于map()与filter()
  4. Mysql之Windows初探
  5. ssh爆破脚本
  6. NOIP2014-提高组初赛C语言解析(选择填空题)
  7. 微信小程序推荐
  8. R安装
  9. F9 开发之左树右表中的左树
  10. 关于string转整数