关于requirejs中的define的原理理解
我们已经了解到模块模式是为单例创建私有变量和特权方法的。
一个最基本的例子:
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,存储在一个根据名字来管理的模块列表中。
以上内容,纯属个人理解,如果有不对之处,还请大家热心指正。
关于requirejs中的define的原理理解的更多相关文章
- requirejs中的define
关于requirejs中的define的原理理解 我们已经了解到模块模式是为单例创建私有变量和特权方法的.一个最基本的例子: var foo=(function(){ var something= ...
- 通过源码理解Spring中@Scheduled的实现原理并且实现调度任务动态装载
前提 最近的新项目和数据同步相关,有定时调度的需求.之前一直有使用过Quartz.XXL-Job.Easy Scheduler等调度框架,后来越发觉得这些框架太重量级了,于是想到了Spring内置的S ...
- RequireJS中的require如何返回模块
requirejs中定义AMD模块规则如下: define(function(){ var ProductManager={ Create:function(){ console.log(" ...
- C#中对IDisposable接口的理解
http://blog.sina.com.cn/s/blog_8abeac5b01019u19.html C#中对IDisposable接口的理解 本人最近接触一个项目,在这个项目里面看到很多类实现了 ...
- Linux VFS中write系统调用实现原理【转】
转自:http://blog.chinaunix.net/uid-28362602-id-3425881.html 目录 用户空间的write函数在内核里面的服务例程为sys_write Vfs_wr ...
- [BS-18] 对OC中不可变类的理解
对OC中不可变类的理解 OC中存在很多不可变的类(如NSString,NSAttributedString,NSArray,NSDictionary,NSSet等),用它们创建的对象存在于堆内存中,但 ...
- 对于requirejs AMD模块加载的理解
个人人为使用模块化加载的优点有三: 1,以我的项目为例:90%为图表展示,使用的是echarts,此文件较大,requirejs可以在同一个版本号(urlArgs)之下缓存文件,那么我就可以在访问登陆 ...
- RequireJS中的require返回模块
requirejs中定义AMD模块规则如下: define(function(){ var ProductManager={ Create:function(){ console.log(" ...
- 关于MySQL中的自联结的通俗理解
关于MySQL中的自联结的通俗理解 前言:最近在通过SQL必知必会这本书学习MySQL的基本使用,在学习中也或多或少遇到了点问题,我也正好分享给大家,我的这篇博客用到的所有表格的代码都是来自SQL必知 ...
随机推荐
- MVC源码解析 - 目录
尽管MVC6和MVC4,5已经有很大不同, 但是, 作为一个普通开发人员, 还真没有资格去选择使用哪个版本. So, 尽管已经是old的版本, 还是再次花点时间去温故知新. 我记得在15年初的时候, ...
- CodeForces 645C Enduring Exodus
枚举,三分. 首先,这$n+1$个人一定是连续的放在一起的.可以枚举每一个起点$L$,然后就是在$[L,R]$中找到一个位置$p$,使得$p4最优,因为越往两边靠,距离就越大,在中间某位置取到最优解, ...
- sw代码问题
1.环境版本问题,myeclipse 配 jdk1.7 不能用jdk1.8 :jdk1.6满足不了代码本身 报错为:The type java.io.ObjectInputStream cannot ...
- 7 -- Spring的基本用法 -- 10...
7.10 高级依赖关系配置 组件与组件之间的耦合,采用依赖注入管理:但基本类型的成员变量值,应直接在代码中设置. Spring支持将任意方法的返回值.类或对象的Field值.其他Bean的getter ...
- Vim快捷键大全
vi(vim)是上Linux非常常用的编辑器,很多Linux发行版都默认安装了vi(vim).vi(vim)命令繁多但是如果使用灵活之后将会大大提高效率.vi是"visual interfa ...
- Ubuntu中Qt5.7.0的安装及opencv2.4.13配置
去官网下载qt-opensource-linux-x64-5.7.0.run,到"下载"目录 Ctrl+Alt+T打开终端 cd /home/jv/下载sudo mv qt-ope ...
- struts2.0中struts.xml配置文件详解
先来展示一个配置文件 <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration ...
- mysql的联合,连接,子查询
- 内存/硬盘/io关系
CPU:工人,干活的,判断以及逻辑处理 硬盘:仓库,原料,数据存储 内存:车间,工人干活的地方,车间中加工原料,当车间中没有原料了,在从仓库中取原料,对原料进行加工 内存本身有一定的存储空间,对内存 ...
- .net 在数据访问层中写一个DBhelper优化类
复习了在学校的时候做的WinForm端的一个学生信息管理系统,用的三层架构,看了一下里面的数据优化类 这个类是用来把对数据库的操作封装成静态方法,增删改查的时候直接调用这个类,减少项目里代码的冗余和方 ...