問答
1.為什么要使用模塊化仁期?
網(wǎng)頁愈趨向Web應用程序,導致JavaScript的體量愈來愈大夯尽,客戶端的代碼模塊化成為迫切需求冶忱。
模塊化編程主要功能在一下方面起到積極作用:
- 代碼維護
- 命名沖突
- 代碼的復用性
- 依賴管理
2.CMD尾菇、AMD、CommonJS 規(guī)范分別指什么?有哪些應用
有了模塊派诬,我們就可以更方便地使用別人的代碼劳淆,想要什么功能,就加載什么模塊千埃。但是憔儿,這樣做有一個前提,那就是大家必須以同樣的方式編寫模塊放可。
目前,通行的Javascript模塊規(guī)范共有兩種:CommonJS和AMD朝刊。
- CommonjJS && AMD
在服務器端耀里,一定要有模塊,與操作系統(tǒng)和其他應用程序互動拾氓,否則根本沒法編程冯挎。node.js的模塊系統(tǒng),就是參照CommonJS規(guī)范實現(xiàn)的咙鞍。也就是說CommonJS是服務器端的模塊規(guī)范
在CommonJS中房官,輸出模塊變量使用module.exports對象,module.exports 對象是模塊的對外接口续滋;
有一個全局性方法require()翰守,用于加載模塊;
//math.js
exports.add = function(x,y){
return x+y
}
//complexAdd.js
var add =require('math').add;
exports.addMultiply = fucntion(x,y,z){
return add(x,y)*z
}
有了服務器端模塊以后疲酌,很自然地蜡峰,大家就想要客戶端模塊。但是朗恳,由于一個重大的局限湿颅,使得CommonJS規(guī)范不適用于瀏覽器環(huán)境(CommonJS采取同步加載方式);
瀏覽器端的模塊,不能采用"同步加載"(synchronous)粥诫,只能采用"異步加載"(asynchronous)油航。這就是AMD規(guī)范誕生的背景;
也就是說怀浆,AMD是客戶端模塊化編程的規(guī)范谊囚。
AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"揉稚。它采用異步方式加載模塊秒啦,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句搀玖,都定義在一個回調(diào)函數(shù)中余境,等到加載完成之后,這個回調(diào)函數(shù)才會運行。
目前芳来,主要有兩個Javascript庫實現(xiàn)了AMD規(guī)范:require.js和curl.js含末,下面以require.js進一步講解AMD的用法。
requireJS是一個工具庫即舌,主要用于客戶端的模塊管理佣盒。它可以讓客戶端的代碼分成一個個模塊,實現(xiàn)異步或動態(tài)加載顽聂,從而提高代碼的性能和可維護性肥惭。它的模塊管理遵守AMD規(guī)范(Asynchronous Module Definition)。
require.js的誕生紊搪,就是為了解決這兩個問題:
(1)實現(xiàn)js文件的異步加載蜜葱,避免網(wǎng)頁失去響應;
(2)管理模塊之間的依賴性耀石,便于代碼的編寫和維護牵囤;
requireJS的基本思想是,通過define方法滞伟,將代碼定義為模塊揭鳞;通過require方法,實現(xiàn)代碼的模塊加載梆奈。
require.js加載
<scirpt src='js/require.js defer async='true' data-main='js/main'>
//defer和async可以實現(xiàn)異步加載require.js資源
//data-main屬性的作用是野崇,指定網(wǎng)頁程序的主模塊
模塊的定義
define方法用于定義模塊,RequireJS要求每個模塊放在一個單獨的文件里鉴裹。按照是否依賴其他模塊舞骆,可以分成兩種情況討論。第一種情況是定義獨立模塊径荔,即所定義的模塊不依賴其他模塊督禽;第二種情況是定義非獨立模塊,即所定義的模塊依賴于其他模塊总处。
獨立模塊情況
//math.js
define(
function(){
var add = function(x,y){
return x+y;
};
return {
add:add
}
}
)
非獨立模塊
//complexMuliply.js
define(['math'],function(math){
var add = math.add;
var addMultiply = function(x,y,z){
return add(x,y)*z
}
return {
addMultiply: addMultiply
}
})
define方法的第一個參數(shù)是一個數(shù)組狈惫,它的成員是當前模塊所依賴的模塊。
define方法的第二個參數(shù)是一個函數(shù)鹦马,當前面數(shù)組的所有成員加載成功后胧谈,它將被調(diào)用。它的參數(shù)與數(shù)組的成員一一對應.這個函數(shù)必須返回一個對象荸频,供其他模塊調(diào)用菱肖。
需要注意的是,回調(diào)函數(shù)必須返回一個對象旭从,這個對象就是你定義的模塊稳强,模塊名默認就是文件名场仲。
** 模塊的加載**
模塊的加載可分為加載規(guī)范模塊和非規(guī)范模塊。
加載規(guī)范模塊
//math.js
require(['math'],function(math){
console.log(math.add(1,1))
})
require()函數(shù)接受兩個參數(shù)退疫。
第一個參數(shù)是一個數(shù)組渠缕,表示所依賴的模塊
第二個參數(shù)是一個回調(diào)函數(shù),當前面指定的模塊都加載成功后褒繁,它將被調(diào)用亦鳞。
加載的模塊會以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊棒坏。
加載非規(guī)范模塊
require.js加載的模塊燕差,必須是按照AMD規(guī)范、用define()函數(shù)定義的模塊俊抵。但是實際上谁不,有許多庫并不符合AMD規(guī)范。
這樣的模塊在用require()加載之前徽诲,要先用require.config()方法,定義它們的一些特征吵血。
舉例來說谎替,underscore和backbone這兩個庫,都沒有采用AMD規(guī)范編寫蹋辅。如果要加載它們的話钱贯,必須先定義它們的特征。
require.config({
shim:{
'underscore':{
exports:'_'
},
'backbone':{
deps:['underscore',''jquery],
exports:'Backbone'
}
}
})
require.config()接受一個配置對象侦另,有一個shim屬性秩命,專門用來配置不兼容的模塊。具體來說褒傅,每個模塊要定義(1)exports值(輸出的變量名)弃锐,表明這個模塊外部調(diào)用時的名稱;(2)deps數(shù)組殿托,表明該模塊的依賴性霹菊。
此外,使用require.config()方法支竹,我們可以對模塊的加載行為進行自定義旋廷。require.config()就寫在主模塊(main.js)的頭部。參數(shù)就是一個對象礼搁,這個對象的paths屬性指定各個模塊的加載路徑饶碘。
require.config({
paths:{
'jquery':'jquery.min',
'underscore':'underscore.min',
'backbone':'backbone.min'
}
})
上面的代碼給出了三個模塊的文件名,路徑默認與main.js在同一個目錄(js子目錄)馒吴。如果這些模塊在其他目錄扎运,比如js/lib目錄瑟曲,則有兩種寫法。
一種是逐一指定路徑绪囱。
require.config({
paths:{
'jquery':'lib/jquery.min',
'underscore':'lib/underscore.min',
'backbone':'lib/backbone.min'
}
})
另一種則是直接改變基目錄(baseUrl)
require.config({
baseUrl:'js/lib',
paths:{
'jquery':'jquery.min',
'underscore':'underscore.min',
'backbone':'backbone.min'
}
})
優(yōu)化器r.js
requireJS提供一個基于node.js的命令行工具r.js测蹲,用來壓縮多個js文件。它的主要作用是將多個模塊文件壓縮合并成一個腳本文件鬼吵,以減少網(wǎng)頁的HTTP請求數(shù)扣甲。
- CMD
CMD(Common Module Definition) 通用模塊定義。該規(guī)范明確了模塊的基本書寫格式和基本交互規(guī)則齿椅。該規(guī)范是在國內(nèi)發(fā)展出來的
在 CMD 規(guī)范中琉挖,一個模塊就是一個文件。代碼的書寫格式如下:
define(factory);
當 factory為對象涣脚、字符串時示辈,表示模塊的接口就是該對象、字符串遣蚀;
factory為函數(shù)時矾麻,表示是模塊的構造方法。
執(zhí)行該構造方法芭梯,可以得到模塊向外提供的接口险耀。
factory 方法在執(zhí)行時,默認會傳入三個參數(shù):require玖喘、exports 和 module:
define(function(require, exports, module) { // 模塊代碼});
//math.js
define(function(require,exports,module){
//為模塊math導出add方法
exports.add = function(x,y){
return x+y;
}
})
//complexAdd.js
define(function(require,exports,module){
var add = require('math').add;//加載math模塊
exports.addMultiply = function(x,y,z){
return add(x,y)*z;
}
})
- 小結
通行的Javascript模塊規(guī)范共有兩種CommonJS和AMD甩牺;
CommonJS是基于Node.js的服務器端的模塊化規(guī)范,AMD(異步模塊定義)是客戶端的模塊化規(guī)范累奈;
此外贬派,CMD(通用模塊定義)是在國內(nèi)發(fā)展出來的客戶端的模塊規(guī)范;
AMD 是 RequireJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出澎媒。
CMD 是 SeaJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出搞乏。
對于依賴的模塊,AMD是提前執(zhí)行旱幼,CMD是延遲執(zhí)行查描。
CMD 推崇依賴就近,AMD 推崇依賴前置柏卤《看如下代碼:
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此處略去 100 行
var b = require('./b')
// 依賴可以就近書寫b.doSomething()// ... })
// AMD 默認推薦的是
define(['./a', './b'], function(a, b) {
// 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()...})
3.如下requirejs配置中, baseUrl 有什么作用?以什么作為基準? paths 的作用和用法是什么?
requirejs.config({
baseUrl: "src/js",
//改變基目錄缘缚,這里基目錄指的是./src/js
paths: {
'jquery': 'lib/bower_components/jquery/dist/jquery.min'
}
}
//paths的作用是指定所依賴的模塊的路徑
);
4.如下 r.js 的打包配置中 baseUrl 是什么? name 是什么
({
baseUrl: "./src/js"http://整個打包配置文件的根目錄
paths: {
'jquery': 'lib/bower_components/jquery/dist/jquery.min'
},//需要打包的模塊所在的文件路徑
name: "main",//指明解析的入口文件
out: "dist/js/merge.js"http://打包文件的輸出
})
r.js -o main-built.js
//module load
//main.js
require.config({
baseUrl:'script',
paths:{
math:'module/math',
complexMultiply:'module/complexMultiply'
}
})
require(['math'],function(math){
console.log(math.add(7,2));
})//3
require(['complexMultiply'],function(complexMultiply){
console.log(complexMultiply.addMultiply(1,2,3));
})//9
//define module
// module/math.js
define(function(){
var add = function(x,y){
return x+y
};
return {
add:add
}
})
// module/complexMultiply.js
define(['math'],function(math){
var add = math.add;
var addMultiply = function(x,y,z){
return add(x,y)*z;
}
return {
addMultiply:addMultiply
}
})
//r.js config
({
baseUrl:'.',
paths:{
math:'module/math',
complexMultiply:'module/complexMultiply'
},
name:'main',
out:'dist/built.js'
})
代碼
【注】
老師任務39的代碼題勾笆,我將使用模塊化編程去開發(fā)接下來的個人主頁,這里就不去重構task15的代碼了桥滨;