关于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必知 ...
随机推荐
- XAF-UI元素概述
XAF框架会根据业务模型自动生成默认的UI.一般来说,您可以使用默认的用户界面,但如果它不符合您的要求,您可以自定义它.要做到这一点,你应该知道UI是由哪些元素组成的,以及你可以自定义什么元素,以实现 ...
- Jquery Form表单取值
之前js取form表单的值都是一个一个的取,数量一多之后容易出错而且烦透了.感谢那些愿意分享的人. 页面定义form,并给form指定id值,里面的元素只要是需要键值对应的都赋予name属性,并且na ...
- DPDK support for vhost-user
转载:http://blog.csdn.net/quqi99/article/details/47321023 X86体系早期没有在硬件设计上对虚拟化提供支持,因此虚拟化完全通过软件实现.一个典型的做 ...
- linux上安装Jmeter
一.首先,你的linux上要有jdk,没有的话请参考上一篇 http://www.cnblogs.com/bigshan-1/p/6242991.html 二.延续上篇的linux用户xiaoming ...
- FileOutputStream flush()
FileOutputStream 继承 OutputStream ,flush方法查看源码方法体为空,所以flush没起到清除缓存的作用 改用BufferedOutputStream再调用flush( ...
- Beego学习笔记——开始
beego简介 beego是一个快速开发Go应用的http框架,他可以用来快速开发API.Web.后端服务等各种应用,是一个RESTFul的框架,主要设计灵感来源于tornado.sinatra.fl ...
- openstack私有云布署实践【16.3 Windows Server2008 R2 只有C盘分区镜像制作】
之所以要只有C盘分区镜像,是因为在创建VM或者调整云主机的硬盘大小时,它能自动扩容.无需人工介入 参考http://www.iyunv.com/thread-45149-1-1.html的灵感 ...
- 面试经典——从输入 URL 到页面加载完的过程中都发生了什么事情?
想要更加了解http协议,猛戳这里 1)把URL分割成几个部分:协议.网络地址.资源路径.其中网络地址指示该连接网络上哪一台计算机,可以是域名或者IP地址,可以包括端口号:协议是从该计算机获取资源的方 ...
- c++ 随手记
强类型的理解 先定义一些基础概念 Program Errors trapped errors.导致程序终止执行,如除0,Java中数组越界访问 untrapped errors. 出错后继续执行,但可 ...
- SpringMVC同时使用<mvc:resources … />和日期转换Formatter时出现问题的解决方法
很久没更新博文了,不是没有学习,而是很多东西记在OneNote里面,收获很多啊,因为各种杂事,所以对于博客很久没更新了. 个人觉得:博客比起OneNote或者为知笔记之类的云笔不同在于博客应该记载的是 ...