模块化其实是一种规范,一种约束,这种约束会大大提升开发效率。将每个js文件看作是一个模块,每个模块通过固定的方式引入,并且通过固定的方式向外暴露指定的内容。
按照js模块化的设想,一个个模块按照其依赖关系组合,最终插入到主程序中。
优点:可以直接调用。
缺点:变量可能会出现重复造成的污染,并且无法进行结构性分类。
function a() {
console.log("a");
}
function b() {
console.log("b");
}
a();
b();
优点:变量不会被直接污染,并且易于分类描述内容。
缺点:会暴露所有成员,内部状态可以被外部改写。
var obj={
_a:false,
a:function () {
console.log("a");
},
b:function () {
console.log("b");
}
};
obj.a();
obj.b();
obj._a=3;
优点:外部代码无法读取到里面的_num变量,保证了变量不被污染。
var obj=(function () {
var _num=3;
return{
a:function () {
console.log(a);
},
set num(value){
_num=value;
},
get num(){
return _num;
}
}
})();
obj.num=5;
console.log(obj.num)//5;
console.log(obj._num)//undefined
obj.a();//a
基本上这种就是模块的写法了,但是单纯的这样描述仍然不算完美,因此我们在其基础上进行了一下的修改。
var module=(function () {
return {
a:1,
b:2,
c:function () {}
}
})();
module=(function (mode) {
mode.d=10;
return mode;
})(module);
如果module没有定义或者没有加载进入,这时候我们可以在带入参数的时候给参数时判断是否存在,不存在给一个空对象。
与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象。
var module=(function () {
return {
a:1,
b:2,
c:function () {
}
}
})();
module=(function (mode) {
mode.d=10;
return mode;
})(module || {});
console.log(module);
独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。
为了在模块内部调用全局变量,必须显式地将其他变量输入模块。
var module1=(function($,YAHOO){
//...
})(jQuery, YAHOO);
2009年,美国程序员Ryan Dahl创造了node.js项目,这标志"Javascript模块化编程"正式诞生。node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require(),用于加载模块。CommonJs规范的特点:
举个例子,入口文件main.js:
//加载b.js,并执行返回的函数
var fn=require("./b");
fn();//打印结果 abc
//加载a.js,将返回的对象赋值给obj,执行obj.b()
var obj=require("./a");
obj.b();//打印结果 1
b.js文件:
//导出函数
module.exports=(function(){
return function(){
console.log("abc");
}
})();
a.js文件:
// 导出对象
module.exports=(function(){
return {
a:1,
b:function(){
console.log(this.a);
}
}
})()
有了服务器端模块以后,很自然地,大家就想要客户端模块。而且最好两者能够兼容,一个模块不用修改,在服务器和浏览器都可以运行。但是,由于Commonjs 使用了Node的api,只能在服务端环境上运行。
Commonjs,可以实现模块同步加载,但只能在服务端环境上运行,客户端如果同步加载依赖的话时间消耗非常大,所以需要一个在客户端上基于Commonjs 但是对于加载模块做改进的文案,于是AMD规范诞生了。
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(前置依赖),这个回调函数才会运行。
AMD与Commonjs一样都是js模块化规范,与Commonjs写法不同,AMD要求有两个参数,第一个参数是一个数组,里面是要加载的模块;第二个参数是加载成功后的回调函数,函数的参数就是模块返回的内容。
require([moudle],callback);
举个例子,Main.js文件:
//加载模块a,并执行里面的b方法
require(["./a"],function(o){
o.b();
})
在定义模块的时候需要使用define函数定义,id是定义模块的名字,dependencies是前置依赖,callback是所有依赖加载完毕之后执行的回调函数。
define(id?, dependencies?, callback);
a.js文件:
define((function(){
return {
a:1,
b:function(){
console.log(this.a);
}
}
})());
AMD的两种写法:
无依赖模块规范,这里我们定义了一个加法和一个乘法的方法,return是返回的方法,这两个方法都被卸载一个固定的模块中。AMD规范不能导出函数。
define(function () {
function add(x,y) {
return x+y;
}
function product(x,y) {
return x*y;
}
return{
add:add,
product:product
}
}());
有依赖模块规范,有依赖表示,该模块中的方法需要用到别的模块,必须依赖于别的模块被加载调用时。定义的时候,第一个参数以数组的形式写入需要加载的前提模块,后面的方法是表示加载完成前置模块后回调的方法,参数对应模块中返回的内容。
define(['myLib'], function(myLib){
function foo(){
myLib.doSomething();
}
return {
foo : foo
};
});
RequireJs是js模块化的工具框架,是AMD规范的具体实现。RequireJs的特点:
RequireJs写法:
“主模块”,意思是整个网页的入口代码。它有点像C语言的main()函数,所有代码都从这儿开始运行。就是一开始就执行了主模块,主模块负责了加载所有的需要模块后开始后续内容的执行。我们在首页中写入以下标签,以确定进入主模块。
<script src="./require.js" data-main="./js/Main" async defer>script>
Main.js 配置文件,使用require下的config方法加载配置内容,注意:该内容必须写在主模块的顶部。这个对象的paths属性指定各个模块的加载路径。
//统一当前路径下
require.config({
paths: {
"index": "./index.js",
"a": "./a.js",
"b": "./b.js"
}
});
//入口文件
require(["index"],function(obj){
obj();
})
index.js文件:
define("index",["a","b"],function(a,b){
return function(){
console.log(a.num+b.num);
}
});
a.js文件:
//函数参数为前置依赖中return 的内容
define("a",["b"],function(BoxObj){
return {
num:3,
run:function(){
var b=new BoxObj.Box(20);
b.play();
}
}
});
b.js文件:
define("b",function(){
return {
num:1,
}
});
使用require下的config方法加载配置各个模块的加载路径时,有以下几种情况:
//各自不同的路径,
//如果这些模块在其他目录,比如js/lib目录,则有两种写法。一是需要逐一指定路径
require.config({
paths: {
"index": "./lib/index.js",
"a": "./lib/a.js",
"b": "./lib/b.js"
}
});
//二是当多个内容基于一个路径下,我们不需要逐一写这些路径,增加baseUrl值是该基路径就可以了。
require.config({
baseUrl: "./lib",
paths: {
"index": "./index.js",
"a": "./a.js",
"b": "./b.js"
}
});
//非本地路径
//如果某个模块在另一台主机上,也可以直接指定它的网址,比如:
require.config({
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
}
});