javascript模块化化编程
一:javascript模块化化编程
javascript起初不是一种模块化编程语言,不支持类(class),也不支持模块(module),但是随着业务的发展,javascript也实现了一些“某模块”的效果,ES6中已经支持“类”和“模块”
javascript模块化编程经历了以下几个阶段:
1:函数式写法
模块就是实现特定功能的一组方法
创建文件m.js:
function m1(){...}
function m2(){...}
m1();
m2();
优点:
简单明了
编写方便
缺点:
污染了全局变量
容易与其他模块的变量名冲突
模块内成员之间没有直接联系
2:对象写法
var module = {
_count:0,
m1:function(){...},
m2:function(){...}
}
module.m1();
module.m2();
优点:
解决了函数式写法的缺点
缺点:
模块成员暴露
模块内部变量容易被修改,eg:module._count=1
3:立即执行函数
var module = (function(){
var _count = 0;
var m1 = function(){...}
var m2 = function(){...}
return {
m1:m1,
m2:m2
}
})()
优点:
不暴露私有成员
外部代码无法访问内部变量
4:继承式写法
是对立即执行函数的加工处理
运行:
var module1 = (function(){
var _count = 0;
var m1 = function(){console.log("m1")};
var m2 = function(){console.log("m2")};
return {
m1:m1,
m2:m2
}
})();
var module1 = (function(mod){
mod.m3 = function(){console.log("m3")};
return mod;
})(module1);
module1.m1();
module1.m2();
module1.m3();
输出:
m1
m2
m3
运行:
var module1 = (function(){
var _count = 0;
var m1 = function(){console.log("m1")};
var m2 = function(){console.log("m2")};
return {
m1:m1,
m2:m2
}
})();
var module2 = (function(mod){
mod.m3 = function(){console.log("m3")};
return mod;
})(module1);
module1.m1();
module1.m2();
module1.m3();
module2.m1();
module2.m2();
module2.m3();
输出:
m1
m2
m3
m1
m2
m3
优点:
模块之间实现了继承
缺点:
立即执行函数的参数不可以为空对象
5:继承式兼容写法
var module1 = (function(){
var _count = 0;
var m1 = function(){console.log("m1")};
var m2 = function(){console.log("m2")};
return {
m1:m1,
m2:m2
}
})();
var module2 = (function(mod){
mod.m3 = function(){console.log("m3")};
return mod;
})(module || {});
module1.m1();
module1.m2();
module2.m3();
输出:
m1
m2
m3
优点:
立即执行函数的对象可以是空对象{}
6:调用全局变量
在模块内部调用全局变量,必须显式地将其他变量输入模块。保证了模块的独立性,使得模块之间的依赖关系变得明
var module = (function($){
...
})(jQuery)
7:总结
立即执行函数有两种写法
(function(){console.log("run1")})();
(function(){console.log("run2")}());
var run3= function(){console.log("run3")}();
var run4= function(){console.log("run4")};
输出:
run1
run2
run3
以下写法是错误的:
function(){console.log("run3")}()
注:最好加上分号运行,否则有可能会语法报错
分析自调用匿名函数
通过定义一个匿名函数,创建一个私有空间,在该空间内定义的变量和方法,外面是访问不了的,应此不会破坏全局命名空间
(function(){console.log("run1")})();
上面这种写法是用第一个括号定义了一个匿名函数,第二个括号执行这个匿名函数,所以会输出run1
(function(){console.log("run2")}());
上面这种写法用外面那个括号强制执行里面的匿名函数
上面两种写法语法上都是对的,二者功能一样,只是运算过程不一样
以上几种写法是传统的js模块写法,模块的好处不言而喻,不过多人开发,必须执行一套规则才能工作,因此出现了CommonJS、AMD以及CMD
8:CommonJS
CommonJS是服务器端的模块化规范,node.js使这个规范的实现,require是用于加载模块,exports是用来定义模块
exports.add = function(){consoe.log("add")}
var add = require("add").add
add()
在上面代码中,是同步加载,由于服务器端不需要网络请求,读取时间很快,因此可以,但是在浏览器端,由于网络等原因,如果采用同步加载,就会造成浏览器会等待很长时间,因此浏览器不能采用CommonJS规范,只能采用异步加载,因此诞生了AMD和CMD
9:AMD
AMD:Asynchronous Module Definition,异步模块定义,采用异步方式加载模块,因此模块的加载不会影响后面语句的运行。所有依赖加载模块的的语句,都定义在一个回调函数中,只有等模块加载完毕,回调函数才会运行,依赖模块的语句才会运行
模块化的好处:
- 异步加载避免网页失去响应
- 实现了模块之间的依赖性,便于维护
AMD也采用require加载模块
语法;
require([module1,module2,...],function(module1,module2){})
define([module1,module2,...],function(module1,module2){})
实现了AMD规范的js是require.js
AMD是提前执行,依赖前置
10:CMD
CMD:Common Module Definition,通用模块定义
语法:
define(function(require,exports,module){
//模块代码
})
实现了CMD规范的js是sea.js
CND是延迟执行,依赖就近
11:require.js
语法:
放在页面底部
<script src="require.js" data-main="main" ></script>
放在页面顶部
<script src="require.js" data-main="main" async = "true"></script>
放在页面顶部,ie
<script src="require.js" data-main="main" defer async = "true"></script>
main.js:
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min"
},
shim: {
'underscore':{
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
}
});
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
//some code here
});
模块的定义1:
//math.js
define(function(){
var add = function(){
var sum = 0,
i = 0,
args = arguments,
len = args.length;
while (i < len){
sum += args[i++]
}
return {
sum:sum
};
}
})
模块的定义2:
define(["module"],function(module){
function foo(){
module.do();
}
return {
foo:foo
}
})
加载此模块
//main.js
require(["math"],function(math){
console.log(math.add(1,2,3))
})