requireJS使用shim注入非标准模块详解
在javascript中定义全局变量有2种方式,本质上是等价的,都是向window对象注入属性或者方法。
// global.js var g_name = "aty"; window.g_age = 25;
当global.js加载的时候,浏览器的全局对象window就会多出2个属性:g_name和g_age。
我们编写一个js工具类或者是js框架,通常有2种方式:
方式1:dateUtil.js
(function(window) {
var DateUtils = {};
DateUtils.toString = function(){
alert("toString");
};
// 全局变量
window.DateUtils = DateUtils;
})(window);
这种方式是最常用的,比如JQuery、Underscore等框架都是采用这种结构编写的。
方式2:stringUtil.js
// 全局变量
var StringUtils = {}; StringUtils.toUpperCase = function(input){
alert("toUpperCase");
}
很显然stringUtil.js和dateUtil.js都不符合AMD规范,现在我们看看如何通过requireJS进行加载。工程目录结构如下:
index.html
main.js
libs
--dateUtil.js
--stringUtil.js
index.html和main.js的实现代码如下:
<!doctype html>
<html>
<head>
<title>shim</title>
<meta charset="utf-8">
<script data-main="main.js" src="./../requirejs-2.1.15.js"></script>
</head>
<body>
<div id="div1" style="width:200px;height:200px;"></div> </body>
</html>
requirejs.config({
baseUrl: 'libs'
});
require(["dateUtil","stringUtil"], function(dateUtil,stringUtil) {
alert(dateUtil===undefined);//true
});
运行index.html,通过F12观察:
很明显dateUtil.js和stringUtil.js能够被requireJS正常加载,但是不能获取到这2个模块的返回值。我们修改下index.html,给div注册事件处理函数,并在事件处理函数中调用stringUtil.js提供的方法:
<!doctype html>
<html>
<head>
<title>shim</title>
<meta charset="utf-8">
<script data-main="main.js" src="./../requirejs-2.1.15.js"></script>
<script>
function test()
{
StringUtils.toUpperCase();
}
</script>
</head>
<body>
<div id="div1" style="width:200px;height:200px;" onclick="test();"></div> </body>
</html>
点击div1,可以发现test()函数不会报错。也就是说,requireJS加载不符合AMD规范的js文件,跟我们直接在html通过<script>标签加载,没有太大的差别。js文件中引入的全局变量,依然会存在,依然能够正常使用。
下面我们看下shim参数的使用方式,我们将main.js修改如下:
requirejs.config({
baseUrl: 'libs',
shim:{
dateUtil:{
deps:[],
exports: 'DateUtils'
},
stringUtil:{
deps:[],
exports: 'StringUtils'
}
}
});
require(["dateUtil","stringUtil"], function(dateUtil,stringUtil) {
stringUtil.toUpperCase();
dateUtil.toString();
});
这段代码可以正常运行,可以看到:shim参数能够帮助我们以AMD模块的方式,使用那些不符合AMD规范的模块。下面接介绍下:deps和exports的含义。exports很好理解,就是模块的返回值。main.js中exports的值,一定要与dateUtil.js和stringUtil.js中暴露出的全局变量名称一致。很显然dateUtil.js和stringUtil.js这2个模块的返回值,就是暴露出的全局变量window.DateUtils和window.StringUtils,requireJS框架就是将这些全局变量的值返回,作为模块的返回结果。如果dateUtil.js或stringUtil.js中暴露了多个全局变量,那么exports可以指定其中任何的一个,作为模块的返回结果。不过一般的框架,都只会使用1个全局变量,这样冲突的可能性会减少,毕竟全局变量越少越好。
上面我们编写的dateUtil.js和stringUtil.js,都不依赖于其他js模块,所以指定的deps是空数组。下面我们编写的aplugin.js和bplugin.js都依赖于模块util.js。
//aplugin.js
(function(window,util) { var a = {}; a.toString = function(){
alert("a="+util.add(1,2));
}; // 全局变量
window.a = a; })(window,util);
//bplugin.js
var b = {};
b.toString = function(){
alert("b="+util.add(1,2));
}
//util.js
var util = {}; util.add = function(v1,v2){
return v1+v2;
};
main.js代码如下,只有设置正确的依赖顺序,使用的时候才不会出问题。
requirejs.config({
baseUrl: 'libs',
shim:{
dateUtil:{
deps:[],
exports: 'DateUtils'
},
stringUtil:{
deps:[],
exports: 'StringUtils'
},
aplugin:{
deps:["util"],
exports: 'a'
},
bplugin:{
deps:["util"],
exports: 'b'
}
}
});
require(["stringUtil","dateUtil","aplugin","bplugin"], function(string,date) {
//string.toString();
//date.toString();
var aPl = require("aplugin");
var bPl = require("bplugin");
aPl.toString();
bPl.toString();
});
很显然util.js也不符合AMD规范,如果A模块依赖于B模块,A模块不符合AMD规范(使用的是全局变量),那么B模块也必须是使用全局变量,否则会报错。即如果将util.js改成符合AMD规范的写法,那么aplugin.js和bplugin.js都会因找不到util对象而报错。
// 符合AMD规范的util.js
define(function(){
function add(v1,v2)
{
return v1+v2;
}
return {"add":add};
});
最后我们看下shim配置参数中init的作用。init可以指定一个函数主要就是用来避免类库之间的冲突。由于不符合AMD规范的js文件,会使用全局变量。所以当加载多个模块的时候存在名字冲突的可能。比如JQuery、UnderScore等框架都会提供一个noConflict()函数来避免名字冲突,noConflict()的实现原理可以参考这篇文章。
我们编写一个不符合AMD规范的模块conflict.js,使用了全局变量$E,并提供noConflict方法。
(function(window) {
// 保存之前数据
var _$E = window.$E;
var myplugin = {"name":"aty"};
myplugin.noConflict = function(){
window.$E = _$E;
return myplugin;
};
// 向全局对象注册$E
window.$E = myplugin;
})(window);
将index.html修改如下,在requireJS加载之前,先定义一个全局变量$E。
<!doctype html>
<html>
<head>
<title>shim</title>
<meta charset="utf-8">
<script>
var $E = "before";
</script>
<script data-main="main.js" src="./../requirejs-2.1.15.js"></script>
</head>
<body>
<div id="div1" style="width:200px;height:200px;" onclick="test();"></div>
</body>
</html>
main.js中代码如下:
requirejs.config({
baseUrl: 'libs',
shim:{
conflict:{
deps:[],
exports: '$E',
init:function(){
return $E.noConflict();
}
}
}
});
require(["conflict"], function(mayConflict) {
alert(mayConflict.name);
alert(window.$E);//before
});
运行index.html,可以发现conflict.js能够与之前定义的全局变量$E共存,避免了冲突,这就是通过init实现的。如果没有定义init,可以看到alert(window.$E)打印的值是undefined。
原文:http://blog.csdn.net/aitangyong/article/details/44225859
requireJS使用shim注入非标准模块详解的更多相关文章
- (转)python标准库中socket模块详解
python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...
- python之sys模块详解
python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...
- Spring学习(一)-----Spring 模块详解
官方下载链接:http://repo.spring.io/release/org/springframework/spring/ Spring 模块详解: Core 模块 spring-beans-3 ...
- (转)python之os,sys模块详解
python之sys模块详解 原文:http://www.cnblogs.com/cherishry/p/5725184.html sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和 ...
- Kali linux 2016.2(Rolling)中的payloads模块详解
不多说,直接上干货! 前期博客 Kali linux 2016.2(Rolling)中的Exploits模块详解 payloads模块,也就是shellcode,就是在漏洞利用成功后所要做的事情.在M ...
- Python中操作mysql的pymysql模块详解
Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ...
- python time模块详解
python time模块详解 转自:http://blog.csdn.net/kiki113/article/details/4033017 python 的内嵌time模板翻译及说明 一.简介 ...
- 小白的Python之路 day5 time,datatime模块详解
一.模块的分类 可以分成三大类: 1.标准库 2.开源模块 3.自定义模块 二.标准库模块详解 1.time与datetime 在Python中,通常有这几种方式来表示时间:1)时间戳 2)格式化的时 ...
- Ansible安装部署及常用模块详解
Ansible命令使用 Ansible语法使用ansible <pattern_goes_here> -m <module_name> -a <arguments> ...
随机推荐
- 350 Intersection of Two Arrays II 两个数组的交集 II
给定两个数组,写一个方法来计算它们的交集.例如:给定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].注意: 输出结果中每个元素出现的次数, ...
- 关于GIT使用过程中遇到的问题
npm构建,将所需要安装的依赖添加至package.json文件中,使用cnpm i进行安装 #拉去指定项目的默认分支: git pull http://username:password@gitla ...
- 研磨JavaScript系列
JavaScript是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言.同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如响应用户的各种操作.它最初由网景公司 ...
- JS——筋斗云案例
需求: 1.鼠标移动到哪里,云彩移动到哪里 2.鼠标离开,云彩回到原点 3.鼠标离开,云彩回到之前点击的地方 <!DOCTYPE html> <html lang="en& ...
- JS——AJAX
向服务器发送请求如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:Open方法了有两种请求方式——get和post 与 POST 相比,GE ...
- JS——标记
continue 语句(带有或不带标签引用)只能用在循环中.break 语句(不带标签引用),只能用在循环或 switch 中.通过标签引用,break 语句可用于跳出任何 JavaScript 代码 ...
- C#的一些知識點
不能將屬性以ref或out的方式傳遞 看上去屬性和字段差不多,可是屬性本質上是個方法,并不是真正指向一個内存位置,所以不能像字段那樣能以ref或out方式傳遞. Lookup運行一個鍵對應多個值,但無 ...
- zabbix配置邮件报警(第四篇)
zabbix配置邮件报警(第四篇) 邮件报警可采用本地邮件服务,也可以自定义脚本,这里我采用本地邮件服务报警 添加收件人
- Centos6.6 安装基于系统认证的vsftp服务
一.介绍 vsftp是一款文件服务器软件,在文件共享,代码更新,文件备份中也是经常用到,以下是基本安装环境: 1)CentOS6.6 2)vsftpd-2.2.2 二.安装 $ yum install ...
- 阿里P8架构师详解Java性能调优策略
一.性能测试 Ⅰ.测试方法 微基准性能测试 可以精准定位到某个模块或者某个方法的性能问题,例如对比一个方法使用同步实现和非同步实现的性能差异 宏基准性能测试 宏基准性能测试是一个综合测试,需要考虑到测 ...