題目1: 為什么要使用模塊化还蹲?
- 解決命名沖突
- 依賴管理
- 提高代碼可讀性
- 代碼解耦,提高復(fù)用性
題目2: CMD耙考、AMD谜喊、CommonJS 規(guī)范分別指什么?有哪些應(yīng)用
- CommonJS
1倦始、CommonJS 是用于服務(wù)器端模塊的規(guī)范斗遏。Node.js采用了這個規(guī)范。Node.JS首先采用了js模塊化的概念鞋邑。
2诵次、定義模塊:根據(jù)CommonJS規(guī)范,一個單獨的文件就是一個模塊枚碗。每一個模塊都是一個單獨的作用域逾一,也就是說,在該模塊內(nèi)部定義的變量肮雨,無法被其他模塊讀取遵堵,除非定義為global對象的屬性。
3怨规、模塊輸出:模塊只有一個出口陌宿,module.exports對象,我們需要把模塊希望輸出的內(nèi)容放入該對象波丰。
4壳坪、加載模塊: 加載模塊使用require方法,該方法讀取一個文件并執(zhí)行掰烟,返回文件內(nèi)部的module.exports對象爽蝴。
//模塊定義 myModel.js
var name = 'Byron';
function printName(){
console.log(name);
}
function printFullName(firstName){
console.log(firstName + name);
}
module.exports = { //module.exports對象是作為模塊出口,方便其他的js調(diào)用
printName: printName,
printFullName: printFullName
}
//加載模塊
var nameModule = require('./myModel.js'); //相當(dāng)于nameModule調(diào)用了JS的require函數(shù)沐批,文件擴展名可省略,該方法讀取一個文件并執(zhí)行霜瘪,返回內(nèi)部的module.exports對象珠插。
nameModule.printName();
//用法:將模塊定義和加載模塊代碼分別放在兩個js文件中(a.js,b.js),然后在bash中執(zhí)行代碼node b.js颖对,結(jié)果會在bash中顯示
缺點:
1捻撑、require("./myModel.js")里的路徑很不好處理
2、當(dāng)執(zhí)行require("./myModel.js")時缤底,瀏覽器要先下載文件顾患,由于是同步運行,所以要等到文件下載完成時才能執(zhí)行个唧,但是CommonJS只支持服務(wù)器端運行江解,不支持瀏覽器運行
- AMD
1、AMD是"Asynchronous Module Definition"的縮寫徙歼,意思就是"異步模塊定義"犁河。
2、它采用異步方式加載模塊魄梯,模塊的加載不影響它后面語句的運行桨螺。
3、所有依賴這個模塊的語句酿秸,都定義在一個回調(diào)函數(shù)中灭翔,等到加載完成之后,這個回調(diào)函數(shù)才會運行辣苏。
4肝箱、由于不是JavaScript原生支持,使用AMD規(guī)范進行頁面開發(fā)需要用到對應(yīng)的庫函數(shù)稀蟋,也就是RequireJS煌张,實際上AMD 是 RequireJS 在推廣過程中對模塊定義的規(guī)范化的產(chǎn)出
5、requireJS主要解決兩個問題:1. 多個js文件可能有依賴關(guān)系糊治,被依賴的文件需要早于依賴它的文件加載到瀏覽器唱矛。2. js加載的時候瀏覽器會停止頁面渲染,加載文件越多井辜,頁面失去響應(yīng)時間越長。
//格式:
//定義模塊:
define(id?, dependencies?, factory); //?表示可選
//id:可選參數(shù)管闷,用來定義模塊的標(biāo)識粥脚,若沒有提供,默認(rèn)為腳本文件名(去掉拓展名)
//dependencies:是一個當(dāng)前模塊依賴的模塊名稱數(shù)組包个,默認(rèn)為["require", "exports", "module"]刷允,若factory的參數(shù)小于3冤留,加載器會選擇參數(shù)個數(shù)調(diào)用工廠方法。
//factory:工廠方法树灶,模塊初始化要執(zhí)行的函數(shù)或?qū)ο笙伺H魹楹瘮?shù),只被執(zhí)行一次天通。若為對象泊窘,應(yīng)該為模塊的輸出值
//在頁面上使用require函數(shù)加載模塊:
require([dependencies], function(){});
//第一個參數(shù)是數(shù)組,表示所依賴的模塊
//第二個參數(shù)是回調(diào)函數(shù)像寒,當(dāng)前面的模塊都加載成功后將被調(diào)用烘豹。加載的模塊會以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊
//require()函數(shù)在加載依賴模塊時是異步加載的诺祸,這樣瀏覽器不會失去響應(yīng)携悯,它的回調(diào)函數(shù)只有模塊都加載成功后才運行,解決了依賴性的問題筷笨。
//例如:
require(['math'], function (math) {
math.add(2, 3);
});
- CMD
1憔鬼、CMD(Common Module Definition) 通用模塊定義。該規(guī)范明確了模塊的基本書寫格式和基本交互規(guī)則胃夏。該規(guī)范是在國內(nèi)發(fā)展出來的轴或。AMD是依賴關(guān)系前置,CMD是按需加載构订。
2侮叮、就像AMD有個requireJS,CMD有個瀏覽器的實現(xiàn)SeaJS悼瘾,SeaJS要解決的問題和requireJS一樣囊榜,只不過Sea.js 推崇一個模塊一個文件,遵循統(tǒng)一的寫法
//定義模塊
define(id?, deps?, factory)
//CMD推崇一個文件一個模塊亥宿,所以經(jīng)常就用文件名作為模塊id卸勺,一般不寫
//CMD推崇依賴就近,所以一般不在define的參數(shù)中寫依賴烫扼,在factory中寫曙求,所以deps參數(shù)省略
//factory: function(require, exports, module){},require 是一個方法映企,接受模塊標(biāo)識作為唯一參數(shù)悟狱,用來獲取其他模塊提供的接口。exports 是一個對象堰氓,用來向外提供模塊接口挤渐。module 是一個對象,上面存儲了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法双絮。
//加載模塊
seajs.use(['myModule.js'], function(my){
});
//例如:
// 定義模塊 myModule.js
define(function(require, exports, module) {
var $ = require('jquery.js')
exports.add=function(){
$('div').addClass('active');
}
});
// 加載模塊
seajs.use(['myModule.js'], function(my){
my.add();
});
題目3: 使用 requirejs 完善入門任務(wù)15浴麻,包括如下功能:
1. 首屏大圖為全屏輪播
2. 有回到頂部功能
3. 圖片區(qū)使用瀑布流布局(圖片高度不一)得问,下部有加載更多按鈕,點擊加載更多會加載更多數(shù)據(jù)(數(shù)據(jù)在后端 mock)
筆記
1软免、CommonJS
//實際使用情況:
//math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
//increment.js
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
//program.js
var inc = require('increment').increment;
var a = 1;
inc(a);
// 2
2宫纬、AMD(Require.js)
//實際使用案例:
// 定義模塊 myModule.js
define(['dependency'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName
};
});
// 加載模塊
require(['myModule'], function (my){
my.printName(); });
3、CMD(Sea.js)
//實際使用情況
// 定義模塊 myModule.js
define(function(require, exports, module) {
var $ = require('jquery.js')
$('div').addClass('active');
});
// 加載模塊
seajs.use(['myModule.js'], function(my){
});
//demo
//math.js
define(function(require, exports, module) {
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
});
//increment.js
define(function(require, exports, module) {
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
});
//program.js
define(function(require, exports, module) {
var inc = require('increment').increment;
var a = 1;
inc(a); // 2
module.id == "program";
});
4膏萧、AMD與CMD區(qū)別
- 最明顯的區(qū)別就是在模塊定義時對依賴的處理不同
1漓骚、AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊
2向抢、CMD推崇就近依賴认境,只有在用到某個模塊的時候再去require
3、同樣都是異步加載模塊挟鸠,AMD在加載模塊完成后就會執(zhí)行該模塊叉信,所有模塊都加載執(zhí)行完后會進入require的回調(diào)函數(shù),執(zhí)行主邏輯艘希,這樣的效果就是依賴模塊的執(zhí)行順序和書寫順序不一定一致硼身,看網(wǎng)絡(luò)速度,哪個先下載下來覆享,哪個先執(zhí)行佳遂,但是主邏輯一定在所有依賴加載完成后才執(zhí)行
4、CMD加載完某個依賴模塊后并不執(zhí)行撒顿,只是下載而已丑罪,在所有依賴模塊加載完成后進入主邏輯,遇到require語句的時候才執(zhí)行對應(yīng)的模塊凤壁,這樣模塊的執(zhí)行順序和書寫順序是完全一致的
5吩屹、requirejs使用步驟
目的: 是代碼的模塊化,它使用了不同于傳統(tǒng)<script>標(biāo)簽的腳本加載步驟拧抖∶核眩可以用它來加速代碼加載、優(yōu)化代碼唧席,但其主要目的還是為了代碼的模塊化擦盾。
- 加載js文件:
<script data-main="scripts/main.js" src="scripts/require.js"></script>
//data-main屬性中的main.js文件,requirejs使用它來啟用腳本加載過程淌哟,當(dāng)頁面加載了requirejs迹卢,立即執(zhí)行main.js文件
//設(shè)置了data-main,baseUrl指向scripts目錄徒仓,也可用requirejs.config({})手動配置(當(dāng)前目錄為html所在目錄婶希,所以要以html所在目錄做為基準(zhǔn)),若兩者都沒蓬衡,baseUrl默認(rèn)指向引用requirejs的html所在的目錄喻杈。
- 設(shè)置main.js文件
//這是目錄表
www/
-index.html
-js/
---app/
------sub.js
---lib/
------jquery.js
------canvas.js
---main.js
//main.js
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app'
}
});
//加載模塊
requirejs(['jquery', 'canvas', 'app/sub'],
function ($, canvas, sub) {
//jquery,canvas,sub 資源都已經(jīng)加載完畢,可以用了狰晚。
});
});
//baseUrl為加載文件的起始位置筒饰,不過請注意的是paths配置(paths是路徑相對于baseUrl而言的,加載的文件都不需要.js后綴壁晒。
//想要避開baseUrl+paths(Module ID)的解析過程瓷们,直接指定加載當(dāng)前HTML頁面目錄下的腳本三種方法:
//腳本以".js"結(jié)束
//以"/"開始
//包含URL協(xié)議,如http:或https:
//canvas.js
define(['app/sub'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName //這是給其他模塊的接口
};
});
//sub.js
define(["canvas"],function(Canvas){
Canvas.printName(); //依賴canvas模塊秒咐,并且引用模塊功能
});
(mission 4)