JS模块化编程(三)
AMD&CMD
- 对象字面量
对象字面量表示,其实就是用一对大括号括起来的键值对,也就是JavaScript 声明对象的方式
var myObject = {
variableKey : variableValue,
functionKey : function() {
...
}
比较一下下面代码声明方式,使用对象字面量表示,可以减少全局变量的污染,
一般来说,强烈建议在任何时候都不要使用下面的声明方式
var variableName = ...;
function f1(){
...
}
function f2(){
...
}
- 立即执行函数(IIFE Immediately-Invoked Function Expressions)
立即执行函数是现在非常流行的写法,大部分JS 库都使用了这种技巧,主要是防止全局变量的污染。
当我们在声明类似于
var name1 = function (){ … } 这样的函数时,
在后面加一对括号(),就可以让它立即执行,但是如果是
function name1() { … }
这样的函数,则会有问题:
function f1(){
alert("ok");
}();//Unexpected token(意外的标记),因为后面的()会被解析为分组操作符
解决上面的问题,只需要加上括号将function 代码全部括住即可,下面就是立即执行函数的声明方式:
(function () { /* code */ } ());
(function () { /* code */ })();
上面两种方式都是可以的,主要看个人习惯。立即执行函数可以不对外暴露私有变量,比如:
var myObject = {
name : "my name",
f1: function(){
return this.name;
}
};
myObject.name; //变量暴露在外
myObject.f1(); //my name
//对比下面立即执行函数隐藏私有变量
var myObject = (function(){
var name = "my name";
return {
f1: function(){
return name;
}
}
})();
myObject.name; //未定义
myObject.f1(); //my name
- 导入全局变量
把全局变量作为参数传递给一个立即执行函数,这样就完成了全局变量的导入,
立即执行函数中可以使用此全局变量的方法,并可以修改(简化)全局变量的名称
var myobj= (function ( jq) {
function f1(){
jq(".class").html("test");
}
return{
f1: f1
};
})( jQuery );
myobj.f1();
- 模块导出
当然,有导入也可以有导出,有时我们不仅要导入全局变量,也要把模块导出到全局空间
供其他模块使用。通过在立即执行函数中返回一个Object,就可以实现模块导出功能:
var myobj = (function () {
var obj = {},
attr1 = "属性1,私有";
function f1() { // ... }
obj.attr2 = "属性2,公共";
obj.f2 = f1;
return obj;
})();
- 扩展模块
在开发中,我们经常会对一些模块进行扩展,扩展当然可以直接修改模块的源代码,
但是这不是一个好的方法,比如我们要给 myModule 模块增加几个方法,
通过前面的“立即执行函数”、“导入全局变量”、“模块导出”的知识,
我们可以推导出下面的扩展方式:
var myobj = (function ( obj ) {
obj.fx = function () {
//...
};
return obj;
})( myobj);
问题来了:上面的代码可以很好地对 myobj 进行扩展,不过前提是 myobj 必须
已经定义,如果扩展的 fx方法和 myobj本身没有任何的依赖,那么要求
myobj必须已经定义就毫无必要了,怎么解决这个问题呢,非常简单,只需要或一个
空对象:
//松散扩展
var myobj = (function ( obj ) {
obj.xxMethod = function () { //...
};
return my;
})( myobj || {} );
上述代码还存在一个问题,那就是如果a.js 中声明了 var myobj= …,b.js 中也声明
了 var myobj= …,这样在引入a.js 和b.js 时,后者会将前者覆盖,这并不是我们期
望的,所以对上述代码,可以再加改进:
(function ( obj ) {
obj.fx= function () {
...
}
})( window.myobj= window.myobj|| {} );
- 再说AMD
是“Asynchronous Module Definition”的缩写,意思就是“异步模块定义”。从名称上就
可以看出,它是通过异步方式加载模块的,模块的加载不影响后续语句的执行,所有依赖
加载中的模块的语句,都会放在一个回调函数中,等到该模块加载完成后,这个回调函数
才运行。
AMD 规范的API 非常简单:
define(id?, dependencies?, factory);
规范定义了一个define 函数,它用来定义一个模块。它包含三个参数,前两个参数都是可选的。
第一个参数 id:是一个string 字符串,它表示模块的标识(也就是模块的路径,通过id 才能知道从什么位置去加载依赖的模块)
第二个参数 dependencies:是一个数组,成员是依赖模块的id
第三个参数 factory:是一个回调函数,在依赖的模块加载成功后,会执行这个回调
函数,它的参数是所有依赖模块的引用,如果回调函数有返回值,会导出出来
一个完整的模块定义包含模块名称,模块的依赖和回调函数,比如下面的代码:
define("addlib", ["math"], function (math) {
return {
addTen : function (x) {
return math.add(x, 10);
}
};
});
如果这个模块并没有依赖,那么默认的依赖是["require", "exports", "module"],这时模块可
以改写为:
define("adder", function (require, exports) {
exports.addTen = function (x) {
return x + 10;
};
});
如果省略第一个参数,则会定义一个匿名模块,见代码:
define(["math"], function (math) {
return {
addTen : function (x) {
return math.add(x, 10);
}
};
});
在实际中,使用的更多的是匿名模块定义方式,因为这样更加的灵活,模块的标识和它的
源代码不再相关,开发人员可以把这个模块放在任意的位置而不需要修改代码。一般只有
在要使用工具打包模块到一个文件中时,才会声明第一个参数,所以应该尽量避免给模块
命名。
在写模块的时候,也有可能没有依赖或者稍后才需要加载依赖,也就是说我们可以省略第
一个和第二个参数,下面代码展示了这种用法,这也是CommonJS 的写法,算是一种兼
容:
define(function (require, exports, module) {
……
var a = require('a'),
b = require('b');
exports.action = function () {
……
};
});
注意上述回调函数里的require 的使用将被自动进行动态加载。
JS模块化编程(三)的更多相关文章
- 从273二手车的M站点初探js模块化编程
前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...
- require.js实现js模块化编程(一)
1.认识require.js: 官方文档:http://requirejs.org/RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的Requ ...
- 初步理解require.js模块化编程
初步理解require.js模块化编程 一.Javascript模块化编程 目前,通行的Javascript模块规范共有两种:CommonJS和AMD. 1.commonjs 2009年,美国程序员R ...
- [转]js模块化编程之彻底弄懂CommonJS和AMD/CMD!
原文: https://www.cnblogs.com/chenguangliang/p/5856701.html ------------------------------------------ ...
- require.js实现js模块化编程(二):RequireJS Optimizer
require.js实现js模块化编程(二):RequireJS Optimizer 这一节,我们主要学习一下require.js所提供的一个优化工具r.js的用法. 1.认识RequireJS Op ...
- Javascript模块化编程(三)require.js的用法及功能介绍
这个系列的第一部分和第二部分,介绍了Javascript模块原型和理论概念,今天介绍如何将它们用于实战.我采用的是一个非常流行的库require.js感兴趣的朋友可以了解下啊 我采用的是一个非常流行的 ...
- js模块化编程之彻底弄懂CommonJS和AMD/CMD!
先回答我:为什么模块很重要? 答:因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块.但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写 ...
- 好文推荐系列-------(5)js模块化编程
本文主要来源于阮一峰的<Javascript模块化编程>系列文章整合,原文地址:http://www.ruanyifeng.com/blog/2012/10/javascript_modu ...
- JS模块化编程(一):CommonJS,AMD/CMD
前言 模块化是什么? 为什么采用模块化? 场景: 一个html,因不同的业务需求开发,会不断的引入js文件.另外,a.js和b.js中的变量或函数必须是全局的,才能暴露给使用方. <script ...
- JS模块化编程(二)
背景 我们常在页面引用js遇到下面情况 <script src="1.js"></script> <script src="2.js&quo ...
随机推荐
- Ansible Playbook 简介
我们去远程执行命令时要使用 command 模块,拷贝文件时要使用 copy 模块,如果我们要操作的东西很多,那就要执行很多条不同模块的命令Playbook 是一个 yaml 配置文件,我们可以把不同 ...
- zabbix创建触发器
1. 增加触发器 配置-->主机-->选择主机-->创建触发器 2. 配置触发器 3.查看触发器的状态 如果有问题会显示红色的问题
- bool和BOOL类型知识集合
知识点一.C语言中有bool类型吗? 转自http://blog.csdn.net/liuqiqi677/article/details/6703615 之前一直都没有注意到,最近在用C语言写DSP算 ...
- 保存对象时碰到的问题-列名 'Discriminator' 无效
今天保存对象时碰到问题: {"列名 'Discriminator' 无效.\r\n列名 'Discriminator' 无效."} 百度了一下,百度找到的一个解决: http:/ ...
- linux添加静态路由
1.使用route命令,查看本机路由直接输入route回车即可.route 命令参数: add 增加路由 del 删除路由 -net 设置到某个网段的路由 -host 设置到 ...
- css布局 - 九宫格布局的方法汇总(更新中...)
目录: margin负值实现 祖父和亲爹的里应外合 换个思路 - li生了儿子帮大忙. 借助absolute方位值,实现自适应的网格布局 cloumn多栏布局 grid display: table: ...
- JSP中使用Spring注入的Bean时需要注意的地方
遇到问题 遇到一个问题:在JSP中,使用Spring注入的Bean对象时,未能正确地获取到想要的对象. 郁闷的是,它也没报错. 研究问题 使用DEBUG功能(好久不在JSP里写Java代码了,都忘了J ...
- MFC 三种消息
在MFC应用程序中传输的消息有三种类型:窗口消息.命令消息和控件通知. (1)窗口消息:WM_XXX 窗口消息(Window Message)一般与窗口的内部运作有关,如:创建窗口.绘制窗口和销毁窗口 ...
- MFC控件CTabCtrl关联变量
1.先建立一个对话框MFC应用程序,然后在工具箱里面把Tab Control控件放到对话框中的合适位置上. 再在对话框类中,将该控件绑定一个变量 用两种方法: 1 ) 自己定义成员变量 CTabCtr ...
- Python GUI编程之WxPython
https://en.wikipedia.org/wiki/WxPython 官网: Overview of wxPython: https://wxpython.org/pages/overview ...