JS中的模块化开发
摘引自:
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
http://developer.51cto.com/art/201305/392668.htm
/***
///1.全局函数写法
function m1(){
}
function m2(){
}
缺点:污染全局变量 无法保证不与其它模块的变量名冲突 模块成员之间没有关系
///2.对象写法
var module = {
_count:1,
m1 : function(){
},
m2: function(){
},
}
缺点:暴露所有模块成员 内部状态可以被外部修改 即外部可以直接修改对象的属性等
module._count=2;
///3.立即执行函数(可以达到不暴露私有成员的目的)
var module = (function(){
var _count = 0;
var m1 = function(){
};
var m2 = function(){
};
return {
m1 : m1,
m2 : m2
}
})()
console.log(module._count);--undefined
///4.放大模块
一个模块分成几个部分,一个模块继承另一个模块,这时才有放大模块
var module = (function(){
var _count = 0;
var m1 = function(){
};
var m2 = function(){
};
return {
m1 : m1,
m2 : m2
}
})();
var module1 = (function(module){
module.m3 = function(){
return 111;
}
})(module);
console.log(module);
///5.宽放大模式
由于模块的各个部分是从网上获取,不知道哪个部分先加载,采用放大模块可能加载一个不存在的空对象,这时候采用宽放大模式
var module1 = (function(module){
})(window.module || {})
///6.独立性输入全局变量
独立性模块内部不与程序的其它部分直接交互
为了在模块内部调用全局变量,可以显示的将其输入模块
这样可以保持模块的独立性,也很显现出模块的依赖特性
var module=(function($,YAHOO){
})(jQuery,YAHOO)
————————————————————————————————————————————————————————
模块的好处:有了模块可以很方便的使用别人的代码,想要啥功能就加载啥模块
考虑到不能瞎写就需要制定一个模块标准。目前的标准有CommonJS和AMD标准
2009美国小伙Ryan Dahl创作了node.js项目把js用于服务器端编程。这标志着模块化正式诞生。在浏览器端有无模块不无大碍,毕竟网页程序的复杂度有限
但是服务器端一定要有模块,与操作系统和其它程序互动否则无法编程。
node.js的模块系统就是参照commonJS规范实现的。在common中有一个全局的require()方法用于加载模块,如
一个math.js数学模块可以如下加载
var math = require("math");
math.add(2,3);-->5
有了服务器端的模块,大家自然想到客户端的模块,最好两者兼容,一个模块不用修改在服务器+客户端浏览器都可以运行。
但是,由于一个重大的局限CommonJS规范不适应于浏览器环境,以上的问题加载math.js可能花费很长时间,对于服务器都在硬盘存储可以同步完成,等待时间就是硬盘加载
的时间。但浏览器就是一个大问题模块放在服务器上,等待时间取决于网络速度,浏览器处于假死状态。因此,浏览器的模块加载不能采用同步(synchronous)只能采用
异步加载的方式(asynchronous)这就是AMD规范的诞生。
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。
所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module], callback);
第一个参数是一个数组,里面的成员是要加载的模块,第二个参数是callback,加载成功后回调的函数。
require(["math"],function(math){
math.add(2,3);
})
math.add()与math模块加载不是同步的,浏览器不会发生假死。所以很显然,AMD比较适合浏览器环境。
目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。
本系列的第三部分,将通过介绍require.js,进一步讲解AMD的用法,以及如何将模块化编程投入实战。
————————————————————————————————————————————————————————
1.为啥要用require.js
最初所有js都写在一个文件里,后来越来越多,分解成多个js.
<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
<script src="4.js"></script>
<script src="5.js"></script>
<script src="6.js"></script>
以上缺点:
加载js时候浏览器会停止渲染,加载文件越多,失去响应的时间就越长
js中存在依赖关系必须保证加载顺序,依赖性最大的模块一定放在最后加载,代码的维护和编写变的困难。
require.js
1.实现js文件的异步加载,避免网页失去响应
2.管理模块之间的依赖,便于代码的编写和维护
加载require.js也可能会出现影响页面响应
解决办法:1.放在网页底部
2.defer async="true" (async这个ie不支持所以写上defer)
data-main="js/main"指定网页程序的主模块默认后缀后缀是.js所以只写main就可以
有点像C语言的main()函数
// main.js
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
由于是异步加载的js所以不会阻塞网页的渲染及响应。回调函数的好处是只有前面的模块加载完成才会调用,解决了依赖问题。。。。
require(['jquery','underscore','backbone'],function($,_,Backbone){
});
默认不写路径,默认与主模块main.js在一个路径。
require.config()可以对模块的加载进行自定义。配置写在主模块中。
require.config({
paths:{
"require":"lib/jquery.min",
"underscore":"lib/underscore.min",
"requbackboneire":"lib/backbone.min"
}
});
require.config({
baseUrl:"js/lib",
paths:{
"require":"jquery.min",
"underscore":"underscore.min",
"requbackboneire":"backbone.min"
}
});
require.config({
baseUrl:"js/lib",
paths:{
"require":"moduleA.min"
}
});
require(['moduleA','moduleB','moduleC'],function(moduleA,moduleB,moduleC){
});
一旦写了baseUrl那么所有的js都依赖这个。
全局路径
require.config({
paths:{
"jquery":"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
}
});
以上要求:
require.js要求每一个模块都是一个单独的js,加载多个模块就会多次http请求,这会影响网页的加载速度。因此提供一个工具来把多个模块合并在一个文件里,减少
请求。
模块必须按照AMD的规范进行书写就是模块必须使用define()函数来定义
如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性
define(["moduleC"], function() {
var name = "a";
return name;
});
理论上讲require.js加载的模块必须用define定义按照AMD的规范。但有一部分的没有按照规范来进行,如下解决。
require.config({
shim: {
'underscore':{
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
}
});
shim属性,专门用来配置不兼容的模块
具体来说,每个模块要定义(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。
jQuery的插件可以这样定义
shim: {
'jquery.scroll': {
deps: ['jquery'],
exports: 'jQuery.fn.scroll'
}
}
require.js插件
require.js还提供一系列插件,实现一些特定的功能。
domready插件,可以让回调函数在页面DOM结构加载完成后再运行。
require(['domready!'], function (doc){
// called once the DOM is ready
});
text和image插件,则是允许require.js加载文本和图片文件。
define([
'text!review.txt',
'image!cat.jpg'
],
function(review,cat){
console.log(review);
document.body.appendChild(cat);
}
);
类似的插件还有json和mdown,用于加载json文件和markdown文件。
require.config({
baseUrl: "fsadfdsfdsa"
})
config这个在开发阶段比较有用,上线压缩成一个文件后不起作用了。
node r.js -o baseUrl=./ name=main out=main-build.js(require.js放哪无关)
**/