為什么要使用模塊化褐筛?
最主要的目的:
解決命名沖突
依賴管理其他價(jià)值:
提高代碼可讀性
代碼解耦杰刽,提高復(fù)用性
CMD焙格、AMD、CommonJS 規(guī)范分別指什么夭问?有哪些應(yīng)用信轿?
CommonJS 規(guī)范:
根據(jù) CommomJS 規(guī)范晃痴,一個(gè)單獨(dú)的文件就是一個(gè)模塊。每一個(gè)模塊都是一個(gè)單獨(dú)的作用域财忽,也就是說倘核,在該模塊內(nèi)部定義的變量,無法被其他模塊讀取即彪,除非定義為global對(duì)象的屬性紧唱。這個(gè)規(guī)范同時(shí)定義了 module.exports 對(duì)象為模塊的出口,我們需要把想要輸出的內(nèi)容放到 module.exports 對(duì)象中;定義了 require 方法為加載模塊的方式漏益。這一規(guī)范主要應(yīng)用在服務(wù)端的JS蛹锰,即NodeJS上。例子如:
// 這里是a.js
var name = 'a';
// 輸出name
module.exports = {
name: name
}
// 這里是b.js
var a = require('a'); // 使用require方法加載模塊绰疤,并返回模塊內(nèi)部的 module.exports 對(duì)象
a.name; // a
AMD 規(guī)范:
AMD 規(guī)范的意思是異步模塊定義的意思,它是一個(gè)在瀏覽器端模塊化開發(fā)的規(guī)范铜犬。由于不是JavaScript原生支持,使用AMD規(guī)范進(jìn)行頁面開發(fā)需要用到對(duì)應(yīng)的庫函數(shù)轻庆,也就是大名鼎鼎RequireJS翎苫,由 RequireJS 在推廣模塊化定義的過程中產(chǎn)出。 這個(gè)規(guī)范用于瀏覽器模塊化的開發(fā)榨了,主要解決了兩個(gè)問題:
- 多個(gè)js文件可能有依賴關(guān)系煎谍,被依賴的文件需要早于依賴它的文件加載到瀏覽器
- 加載的時(shí)候?yàn)g覽器會(huì)停止頁面渲染,加載文件越多龙屉,頁面失去響應(yīng)時(shí)間越長
語法:
requireJS定義了一個(gè)函數(shù) define呐粘,它是全局變量,用來定義模塊
define(id?, dependencies?, factory);
- id:可選參數(shù)转捕,用來定義模塊的標(biāo)識(shí)作岖,如果沒有提供該參數(shù),腳本文件名(去掉拓展名)
- dependencies:是一個(gè)當(dāng)前模塊依賴的模塊名稱數(shù)組
- factory:工廠方法五芝,模塊初始化要執(zhí)行的函數(shù)或?qū)ο蠖焕堋H绻麨楹瘮?shù),它應(yīng)該只被執(zhí)行一次枢步。如果是對(duì)象沉删,此對(duì)象應(yīng)該為模塊的輸出值
在頁面上使用require函數(shù)加載模塊
require([dependencies], function(){});
require()函數(shù)接受兩個(gè)參數(shù)
- 第一個(gè)參數(shù)是一個(gè)數(shù)組,表示所依賴的模塊
- 第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù)醉途,當(dāng)前面指定的模塊都加載成功后矾瑰,它將被調(diào)用。加載的模塊會(huì)以參數(shù)形式傳入該函數(shù)隘擎,從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊
require()函數(shù)在加載依賴的函數(shù)的時(shí)候是異步加載的殴穴,這樣瀏覽器不會(huì)失去響應(yīng),它指定的回調(diào)函數(shù)货葬,只有前面的模塊都加載成功后采幌,才會(huì)運(yùn)行,解決了依賴性的問題震桶。
例子如:
// 這里是a.js
// define函數(shù)的第一個(gè)參數(shù)為依賴項(xiàng)數(shù)組休傍,即想要加載的模塊:例如jquery
// 第二個(gè)參數(shù)為回調(diào)函數(shù),等模塊加載完畢后會(huì)把加載的模塊傳到回調(diào)函數(shù)里
define(['jquery'], function ($) {
var name = 'a';
return {
name: name
} // 這里是模塊輸出尼夺,讓別的模塊能夠使用
});
// 這里是b.js
// 加載模塊a
// 等到所有模塊都加載完畢后再執(zhí)行回調(diào)函數(shù)并把模塊傳到回調(diào)函數(shù)
require(['jquery', 'a'] function ($, a) {
a.name; // a
})
CMD 規(guī)范:
CMD 即Common Module Definition通用模塊定義尊残,CMD規(guī)范是國內(nèi)發(fā)展出來的炒瘸,CMD 規(guī)范與 AMD 規(guī)范類似,就像AMD有個(gè)requireJS寝衫,CMD有個(gè)瀏覽器的實(shí)現(xiàn)SeaJS顷扩,SeaJS要解決的問題和requireJS一樣,只不過在模塊定義方式和模塊加載(可以說運(yùn)行慰毅、解析)時(shí)機(jī)上有所不同但兩者的模塊加載時(shí)機(jī)和模塊定義的方式不同隘截。使用這個(gè)規(guī)范的主要是 SeaJS。
語法
Sea.js 推崇一個(gè)模塊一個(gè)文件汹胃,遵循統(tǒng)一的寫法
define
define(id?, deps?, factory)
因?yàn)镃MD推崇
- 一個(gè)文件一個(gè)模塊婶芭,所以經(jīng)常就用文件名作為模塊id
- CMD推崇依賴就近,所以一般不在define的參數(shù)中寫依賴着饥,在factory中寫
factory有三個(gè)參數(shù)
function(require, exports, module)
require 是 factory 函數(shù)的第一個(gè)參數(shù)
require(id)
require 是一個(gè)方法犀农,接受 模塊標(biāo)識(shí) 作為唯一參數(shù),用來獲取其他模塊提供的接口
exports
exports 是一個(gè)對(duì)象宰掉,用來向外提供模塊接口
module
module 是一個(gè)對(duì)象呵哨,上面存儲(chǔ)了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法
例子如:
// 這里是a.js
define(function (require, module, exports) {
var $ = require('jquery'); // 與AMD規(guī)范不同的是,CMD規(guī)范是要用到模塊的時(shí)候再加載轨奄,而AMD規(guī)范是先把所有模塊加載完后再用
$('div').addClass('active');
})
// 這里是b.js
// 使用模塊a
seajs.use(['a.js'], function(a){
// todo
});
AMD與CMD區(qū)別(關(guān)于這兩個(gè)的區(qū)別網(wǎng)上搜出一堆文章孟害,簡單總結(jié)一下)
最明顯的區(qū)別就是在模塊定義時(shí)對(duì)依賴的處理不同
- AMD推崇依賴前置,在定義模塊的時(shí)候就要聲明其依賴的模塊
- CMD推崇就近依賴挪拟,只有在用到某個(gè)模塊的時(shí)候再去require
這種區(qū)別各有優(yōu)劣挨务,只是語法上的差距,而且requireJS和SeaJS都支持對(duì)方的寫法
AMD和CMD最大的區(qū)別是對(duì)依賴模塊的執(zhí)行時(shí)機(jī)處理不同玉组,注意不是加載的時(shí)機(jī)或者方式不同
同樣都是異步加載模塊谎柄,AMD在加載模塊完成后就會(huì)執(zhí)行該模塊,所有模塊都加載執(zhí)行完后會(huì)進(jìn)入require的回調(diào)函數(shù)球切,執(zhí)行主邏輯谷誓,這樣的效果就是依賴模塊的執(zhí)行順序和書寫順序不一定一致,看網(wǎng)絡(luò)速度吨凑,哪個(gè)先下載下來,哪個(gè)先執(zhí)行户辱,但是主邏輯一定在所有依賴加載完成后才執(zhí)行
CMD加載完某個(gè)依賴模塊后并不執(zhí)行鸵钝,只是下載而已,在所有依賴模塊加載完成后進(jìn)入主邏輯庐镐,遇到require語句的時(shí)候才執(zhí)行對(duì)應(yīng)的模塊恩商,這樣模塊的執(zhí)行順序和書寫順序是完全一致的
這也是很多人說AMD用戶體驗(yàn)好,因?yàn)闆]有延遲必逆,依賴模塊提前執(zhí)行了怠堪,CMD性能好揽乱,因?yàn)橹挥杏脩粜枰臅r(shí)候才執(zhí)行的原因