主要內容
什麼是模塊化為什麼使用模塊化模塊嵌套Requirejs使用學習目標
第一節 什麼是模塊化
1.1 模塊化產生
模塊化發展歷程
js一開始並沒有模塊化的概念,直到ajax被提出,前端能夠像後端請求數據,前端邏輯越來越複雜,就出現了許多問題:全局變量,函數名衝突,依賴關係不好處理。當時使用子執行函數來解決這些問題,比如經典的jquery就使用了匿名自執行函數封裝代碼,將他們全都掛載到全局變量jquery下邊
在js出現的時候,js一般只是用來實現一些簡單的交互,後來js開始得到重視,用來實現越來越複雜的功能,而為了維護的方便,我們也把不同功能的js抽取出來當做一個js文件,但是當項目變的複雜的時候,一個html頁面可能需要加載好多個js文件,而這個時候就會出現各種命名衝突,如果js也可以像java一樣,把不同功能的文件放在不同的package中,需要引用某個函數或功能的時候,import下相關的包,這樣可以很好的解決命名衝突等各種問題,但是js中沒有模塊的概念,又怎麼實現模塊化呢
模塊化開發是一種管理方式,是一種生產方式,一種解決問題的方案,一個模塊就是實現特定功能的文件,有了模塊,我們就可以更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊,但是模塊開發需要遵循一定的規範,否則就都亂套了,因此,才有了後來大家熟悉的AMD規範,CMD規範
1.2為什麼使用模塊化
使用模塊化可以給我們帶來以下好處
解決命名衝突提供復用性提高代碼可維護性靈活架構,焦點分離,方便模塊間組合、分解 多人協作互不幹擾 1.3 js作用域
Js的作用域是函數作用域
代碼:var name='zhangsan';//全局function demo(){var name='lisi';//局部}for(var i=0;i<100;i++){var age=10;//全局}//下面代碼執行的結果?var arr=[10,20,30,40,50];for(var i=0;i<arr.length;i++){arr[i]=function(){console.log(i);}}arr[2]();//列印結果?
結果分析:
怎麼獲取當前的下標對應的數據
//閉包解決 變量作用域問題---var arr=[10,20,30,40,50];for(var i=0;i<arr.length;i++){arr[i]=(function(i){return function(){console.log(i);}})(i);}arr[3]();//列印結果?
本章作業
1.什麼是模塊化
2.為什麼使用模塊化
3.js作用域問題怎麼解決
第二節 模塊化實現
2.1 模塊的出現
//對象問題var obj={name:'lilei',age:20}//需求:我要修改對象的值obj.name='zhaos' //思考這樣修改方式合理嗎???
如果這是一個公共類,公共的屬性和方法,大家都去修改,誰想修改就去修改,這樣就亂了,這樣不合理,我們應該統一修改。
一個公共類我應該是統一修改 或者是統一不修改
2.1.1初步優化方案
思路:把這個對象 封裝一個方法
//寫一個函數 自執行函數 外部不能訪問我的內部內容--創建一個自執行函數(function(){var obj={name:'lisi',age:20}})();console.log(obj);
這樣我們就不能訪問了,但是也不可能寫了方法 不再外部使用,再次優化,我們給外部提供一個修改方案
2.1.2再次優化
//提供外部訪問方式var module=(function(){var obj={name:"lilei",age:20}function setName(value){obj.name=value;console.log(obj.name)}return setName;})();//注意:這是自執行函數,進入直接執行,沒有辦法調用,所以呢我們可以給一個名字// 然後去調用return的結果module('zhangsan');
2.1.3 優化
//上面調用 不好看 不直接 不知道修改的什麼var module=(function(){var obj={name:"lilei",age:20}function setName(value){obj.name=value;console.log(obj.name)}return {setName:setName};})();module.setName('huahua');
2.1.4修改和獲取
var module=(function(){var obj={name:"lilei",age:20}function setName(value){obj.name=value;}function getName(){return obj.name;}return {setName:setName,getName:getName};})();console.log(module.getName());console.log('---------------------');module.setName('huahua');console.log(module.getName());
這時候就有統一標準,誰調用或者修改這個代碼就可以看到,調用這個方法知道那個方法。
總結:這樣比隨便修改這個值要好很多,我們寫的代碼就被為模塊
我們通過模塊把我們的代碼整理和隔離,這樣我們以後寫的功能 公共的使用的方法或者模塊就可以這樣寫,對代碼進行隔離,模塊之前這樣不能直接互相通信,實現隔離
2.1.5 模塊和模塊化區別?
模塊:是用於在項目中劃分相對獨立的功能,模塊更偏重邏輯上區分
模塊化:是從代碼邏輯的角度進行劃分的,方便代碼分層開發,保證每個公能模塊的職能單一
2.2 模塊實現
<!-- 獲取元素---設置元素--用模塊寫 --><div id="box"></div><script>var moduleDOM=(function(){//1.獲取內容function getElement(id){return document.getElementById(id);}//2.設置function setElement(id,value){getElement(id).innerHTML=value;}return {getElement:getElement,setElement:setElement}})();//獲取元素console.log(moduleDOM.getElement('box'));moduleDOM.setElement('box','hello');var content='<h2>我是一個測試數據</h2>';moduleDOM.setElement('box',content);</script>
2.3 模塊的嵌套
如果一個模塊很大,必須分成幾個部分,或者一個模塊需要繼承另一個模塊,這時就有必要採用"放大模式"(augmentation)
/*模塊的嵌套 模塊之前是獨立的 不能直接相互訪問*/var domElement=(function(){function getElement(id){return document.getElementById(id);}return {getElement:getElement}})();var divMoudle=(function(domElement){function setName(id,value){return domElement.getElement(id).innerHTML=value;}return {setName:setName}})(domElement);divMoudle.setName('root','hello!!');
【代碼演示】
模塊的嵌套 實現在當前的模塊使用其他模塊裡面的方法---傳遞進入//傳遞一個jquery 比如下面使用jquery對象var domElement=(function(){function getElement(id){return document.getElementById(id);}return {getElement:getElement}})();var divMoudle=(function(domElement,$){function setName(id,value){return domElement.getElement(id).innerHTML=value;}console.log($);return {setName:setName}})(domElement,$);//jQuerydivMoudle.setName('root','hello!!');
2.4 模塊的放大模式
在瀏覽器環境中,模塊的各個部分通常都是從網上獲取的,有時無法知道哪個部分會先加載。如果採用上一節的寫法,第一個執行的部分有可能加載一個不存在空對象,這時就要採用"寬放大模式",這樣一個比較完整的模塊也就出來了
如果這時候有個人把 獲取元素的模塊置空了,domElement=null;
//模塊的放大模式 模塊的寬大模式 容錯處理var domElement=(function(){function getElement(id){return document.getElementById(id);}return {getElement:getElement}})();domElement=null;var divMoudle=(function(domElement,$){//判斷domElement是否存在if(domElement){function setName(id,value){return domElement.getElement(id).innerHTML=value;}console.log($);return {setName:setName}}else{console.log('domElement對象不存在')}})(domElement,$);//jQuerydivMoudle.setName('root','hello!!');
上面咱們寫的模塊化是很古老的一種寫法
現在我們寫模塊化,藉助於requirejs
Requirejs給大家演示使用方案,在前幾年很多人用的,這2年隨著vue react的框架層出不窮,而且越來越好,現在requrejs的現在使用的人在逐漸減少,但是他的思維方式和寫代碼的方式方法,還是很值得大家思考的。
有個好的詞彙:組件化和模塊化 多模塊化思想(組件化就是vue 模塊化就是requirejs給我們提供的一種思想,其實這兩個沒有太大區別)
本章作業
1.模塊化實現獲取和設置本地元素
2.模塊化的放大模式
第三節requirejs
3.1 模塊化規範的產生
在模塊化規範形成之前,JS開發者使用Module設計模式來解決JS全局作用域的汙染問題。Module模式最初被定義為一種在傳統軟體工程中為類提供私有和公有封裝的方法。在JavaScript中,Module模式使用匿名函數自調用 (閉包)來封裝,通過自定義暴露行為來區分私有成員和公有成員。
var myModule = (function (window) {var moduleName = 'module' // private// publicfunction setModuleName(name) {moduleName = name}function getModuleName() {return moduleName}return { setModuleName, getModuleName } // 暴露行為})(window)
上面例子是Module模式的一種寫法,它通過閉包的特性打開了一個新的作用域,緩解了全局作用域命名衝突和安全性的問題。但是,開發者並不能夠用它來組織和拆分代碼,於是乎便出現了以此為基石的模塊化規範。
RequireJS是一個JavaScript文件或者模塊的加載器。它可以提高JavaScript文件的加載速度,避免不必要的堵塞。它針對於在瀏覽器環境中使用做過專門的優化,但它也可以在其他的JavaScript環境中使用,像Node.js一樣可以在伺服器上運行
3.2為什麼要用require.js
最早的時候,所有Javascript代碼都寫在一個文件裡面,只要加載這一個文件就夠了。後來,代碼越來越多,一個文件不夠了,必須分成多個文件,依次加載。下面的網頁代碼,相信很多人都見過。
<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文件之間存在依賴關係,因此必須嚴格保證加載順序(比如上例的1.js要在2.js的前面),依賴性最大的模塊一定要放到最後加載,當依賴關係很複雜的時候,代碼的編寫和維護都會變得困難。
require.js的誕生,就是為了解決這兩個問題:
(1)實現js文件的異步加載,避免網頁失去響應;
(2)管理模塊之間的依賴性,便於代碼的編寫和維護
(3)命名衝突
3.3 requrejs官網
其實用requirejs就是推薦我們在寫代碼的時候,推薦我們使用模塊化的方式去寫我們的js
目錄解構
js
apps:index.js … 自己定義的js文件
libs:requirejs文件
main.js 配置文件路徑 入口函數
index.html
3.4 使用步驟
1.引入 requirejs
<scrpt data-main=』js/main.js』 src=』js/libs/rrquire.js』></script>
2.創建入口文件:main.js
requirejs.config({baseUrl:』js/』,//基礎路徑配置 paths:{ 「index」:」apps/index」, 「demo」:」apps/demo」}})requirejs([「index」,」demo」,function(index,demo){}]);
代碼效果:
3.引入jquery文件
文件加載效果
注意:創建的文件需要main.js加載 否則不能使用
本章作業
1.理解模塊化的由來
2.requirejs使用的好處
3.如何使用requirejs步驟
第四節 實例
4.1 Requirejs模塊
Js中文件與文件之前是不隔離的,可以相互訪問的,但是我們希望文件是隔離的,不能隨意訪問的,提供訪問方案
4.1.1 定義模塊 簡單名稱/價值對
如果模塊沒有任何依賴關係,並且它只是一個名稱/值對的集合,那麼只需將對象文字傳遞給define():
define({color: "black",size: "unisize"});
4.1.2定義函數
define(function() {return {color: "black",size: "unisize"}});
4.1.3 具有依賴關係的定義函數
如果模塊具有依賴關係,則第一個參數應該是一個依賴關係名稱數組,第二個參數應該是一個定義函數。一旦所有依賴關係被加載,該函數將被調用來定義模塊。該函數應該返回一個定義模塊的對象。依賴關係將被傳遞給定義函數作為函數參數,其順序與依賴關係數組中的順序相同
define(['data'],function(data){console.log(data)})
注意:依賴注入 (想使用data文件 注入data裡面就好了,哪裡使用注入就好了) 依賴前置
4.1.4 定義與簡體CommonJS的包裝一個模塊
如果您希望重用一些以傳統CommonJS模塊格式編寫的代碼,可能難以重新使用上面所使用的依賴關係數組,並且您可能希望將依賴項名稱直接對齊到用於該方法的本地變量依賴(nodejs的模塊化)
define(function(require,exports,module){var data=require("data"); console.log(data)})
這是什麼時候使用什麼時候引用 (依賴就近)
其他的定義模塊使用我們不再去看 我們常用這四種定義方式
4.1.5 獲取dom元素
創建一個DOMElement.js:
define(['jquery'],function(){//定義函數 function setHtml(className,value){ $("."+className).html(value); } return { setHtml:setHtml }})
Index.js
define(["data",'DOMElement'], function(data,DOMElement) {console.log(data); DOMElement.setHtml('box','hello world'); });
4.2 requirejs網易雲音樂
實現 網易雲音樂數據列表展示,點擊音樂播放
步驟
1. 目錄結構創建
2. main.js入口文件
3.http.js
4.index.js
5.config文件
6.view.js顯示視圖
7.點擊音樂列表音樂播放 view.js
4.3 Requirejs的shim
Requirejs所有文件都是define() ,引入第三種也是這種寫法?不是
為什麼jquery可以,Requirejs支持jquery的使用,但是很多第三方插件不支持,使用shim
實例:swiper第三方使用
代碼:
目錄結構:
Index.js
Main.js
Index.js
Index.html
4.4 模塊化規範
AMD 是 RequireJS 在推廣過程中對模塊定義的規範化產出CMD是SeaJS在推廣過程中對模塊化定義的規範化產出區別:
對於依賴的模塊,AMD是提前執行,CMD是延遲執行。不過RequireJS從2.0開始,也改成了可以延遲執行(根據寫法不同,執行的方式不同)CMD推崇就近依賴,AMD推崇依賴前置。看代碼//CMD的方式define(function(require,exprots,module){var a = require('./a');a.dosmting();//省略1W行var b = require('./b');b.dosmting();})
//AMD的方式define(['./a','./b'],function(a,b){a.dosmting();//省略1W行b.dosmting();})
以上AMD的寫法是官方推崇的方式,但是同時也支持CMD的寫法
AMD和CMD最明顯的區別就是在模塊定義時對依賴的處理不同AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊CMD推崇就近依賴,只有在用到某個模塊的時候再去require
本章作業
1.requirejs的定義方式
2.requirejs網易雲實例
3.requirejs導入第三方插件
本文由尚學堂前端學院原創,歡迎關注,帶你一起學習Web前端知識!