導航:首頁 > 編程語言 > js的模塊化編程

js的模塊化編程

發布時間:2023-07-11 06:00:02

❶ 如何理解前端模塊化

前端模塊化
javaScript發展初期就是為了實現簡單的頁面交互邏輯,寥寥數語即可;如今CPU、瀏覽器性能得到了極大的提升,很多頁面邏輯遷移到了客戶端(表單驗證等),隨著web2.0時代的到來,Ajax技術得到廣泛應用,jQuery等前端庫層出不窮,前端代碼日益膨脹

這時候JavaScript作為嵌入式的腳本語言的定位動搖了,JavaScript卻沒有為組織代碼提供任何明顯幫助,甚至沒有類的概念,更不用說模塊(mole)了,JavaScript極其簡單的代碼組織規范不足以駕馭如此龐大規模的代碼

模塊
既然JavaScript不能handle如此大規模的代碼,我們可以借鑒一下其它語言是怎麼處理大規模程序設計的,在Java中有一個重要帶概念——package,邏輯上相關的代碼組織到同一個包內,包內是一個相對獨立的王國,不用擔心命名沖突什麼的,那麼外部如果使用呢?直接import對應的package即可

import java.util.ArrayList;
遺憾的是JavaScript在設計時定位原因,沒有提供類似的功能,開發者需要模擬出類似的功能,來隔離、組織復雜的JavaScript代碼,我們稱為模塊化。

一個模塊就是實現特定功能的文件,有了模塊,我們就可以更方便地使用別人的代碼,想要什麼功能,就載入什麼模塊。模塊開發需要遵循一定的規范,各行其是就都亂套了

規范形成的過程是痛苦的,前端的先驅在刀耕火種、茹毛飲血的階段開始,發展到現在初具規模,簡單了解一下這段不凡的歷程

函數封裝
我們在講函數的時候提到,函數一個功能就是實現特定邏輯的一組語句打包,而且JavaScript的作用域就是基於函數的,所以把函數作為模塊化的第一步是很自然的事情,在一個文件裡面編寫幾個相關函數就是最開始的模塊了

function fn1(){
statement
}

function fn2(){
statement
}
這樣在需要的以後夾在函數所在文件,調用函數就可以了

這種做法的缺點很明顯:污染了全局變數,無法保證不與其他模塊發生變數名沖突,而且模塊成員之間沒什麼關系。

對象
為了解決上面問題,對象的寫法應運而生,可以把所有的模塊成員封裝在一個對象中

var myMole = {
var1: 1,

var2: 2,

fn1: function(){

},

fn2: function(){

}
}
這樣我們在希望調用模塊的時候引用對應文件,然後

myMole.fn2();
這樣避免了變數污染,只要保證模塊名唯一即可,同時同一模塊內的成員也有了關系

看似不錯的解決方案,但是也有缺陷,外部可以隨意修改內部成員

myModel.var1 = 100;
這樣就會產生意外的安全問題

立即執行函數
可以通過立即執行函數,來達到隱藏細節的目的

var myMole = (function(){
var var1 = 1;
var var2 = 2;

function fn1(){

}

function fn2(){

}

return {
fn1: fn1,
fn2: fn2
};
})();
這樣在模塊外部無法修改我們沒有暴露出來的變數、函數

上述做法就是我們模塊化的基礎,目前,通行的JavaScript模塊規范主要有兩種:CommonJS和AMD

CommonJS
我們先從CommonJS談起,因為在網頁端沒有模塊化編程只是頁面JavaScript邏輯復雜,但也可以工作下去,在伺服器端卻一定要有模塊,所以雖然JavaScript在web端發展這么多年,第一個流行的模塊化規范卻由伺服器端的JavaScript應用帶來,CommonJS規范是由NodeJS發揚光大,這標志著JavaScript模塊化編程正式登上舞台。

定義模塊
根據CommonJS規范,一個單獨的文件就是一個模塊。每一個模塊都是一個單獨的作用域,也就是說,在該模塊內部定義的變數,無法被其他模塊讀取,除非定義為global對象的屬性

模塊輸出:
模塊只有一個出口,mole.exports對象,我們需要把模塊希望輸出的內容放入該對象

載入模塊:
載入模塊使用require方法,該方法讀取一個文件並執行,返迴文件內部的mole.exports對象

❷ requirejs模塊化編程怎麼理解

一、Javascript模塊化編程

目前,通行的Javascript模塊規范共有兩種:CommonJS和AMD。

1、commonjs

2009年,美國程序員Ryan Dahl創造了node.js項目,將javascript語言用於伺服器端編程,這標志」Javascript模塊化編程」正式誕生。

在瀏覽器環境下,沒有模塊也不是特別大的問題,畢竟網頁程序的復雜性有限;但是在伺服器端,一定要有模塊,與操作系統和其他應用程序互動,否則根本沒法編程。

node.js的模塊系統,就是參照CommonJS規范實現的。在CommonJS中,有一個全局性方法require(),用於載入模塊。

假定有一個數學模塊math.js,就可以像下面這樣載入。

var math = require('math');

然後,就可以調用模塊提供的方法:

var math = require('math');

math.add(2,3); // 5

因為這個系列主要針對瀏覽器編程,不涉及node.js,所以對CommonJS就不多做介紹了。我們在這里只要知道,require()用於載入模塊就行了。

2、AMD

AMD是」Asynchronous Mole Definition」的縮寫,意思就是」非同步模塊定義」。它採用非同步方式載入模塊,模塊的載入不影響它後面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到載入完成之後,這個回調函數才會運行。

模塊定義
define(id?, dependencies?, factory);
其中:

id: 模塊標識,可以省略。
dependencies: 所依賴的模塊,可以省略。
factory: 模塊的實現,或者一個JavaScript對象。

模塊載入

AMD也採用require()語句載入模塊,但是不同於CommonJS,它要求兩個參數:
require([mole], callback);

第一個參數[mole],是一個數組,裡面的成員就是要載入的模塊;第二個參數callback,則是載入成功之後的回調函數。如果將前面的代碼改寫成AMD形式,就是下面這樣:

require(['math'], function (math) {
math.add(2, 3);
});

math.add()與math模塊載入不是同步的,瀏覽器不會發生假死。所以很顯然,AMD比較適合瀏覽器環境。

目前,主要有兩個Javascript庫實現了AMD規范:require.js和curl.js。本系列的第三部分,將通過介紹require.js,進一步講解AMD的用法,以及如何將模塊化編程投入實戰。

二、requirejs模塊化編程

require.js載入的模塊,採用AMD(非同步模塊定義規范) 規范。也就是說,模塊必須按照AMD的規定來寫。

require.js的兩個重要的特點:

1、實現js文件的非同步載入,避免網頁失去響應

2、管理模塊之間的依賴性,便於代碼的編寫和維護

載入requirejs:

<script src="js/require.js" data-main="js/main"></script>

data-main屬性的作用是,指定網頁程序的主模塊。在上例中,就是js目錄下面的main.js,這個文件會第一個被require.js載入。由於require.js默認的文件後綴名是js,所以可以把main.js簡寫成main。

main.js常見實例:

require.config({
paths: {
moleA: '',
moleB:'',
moleC:''
}
});

require(['moleA', 'moleB', 'moleC'], function (moleA, moleB, moleC){
// some code here

});

1、require.config

require.config用來配置一些參數,它將影響到requirejs庫的一些行為。

require.config的參數是一個JS對象,常用的配置有baseUrl,paths等。

這里配置了paths參數,使用模塊名「jquery」,其實際文件路徑jquery-1.7.2.js(後綴.js可以省略)。

我們知道jQuery從1.7後開始支持AMD規范,即如果jQuery作為一個AMD模塊運行時,它的模塊名是「jquery」。注意「jquery」是固定的,不能寫「jQuery」或其它。

註:如果文件名「jquery-1.7.2.js」改為「jquery.js」就不必配置paths參數了。

如果將jQuery應用在模塊化開發時,其實可以不使用全局的,即可以不暴露出來。需要用到jQuery時使用require函數即可。

2、require()函數

require()函數接受兩個參數。第一個參數是一個數組,表示所依賴的模塊,上例就是['moleA', 'moleB',
'moleC'],即主模塊依賴這三個模塊;第二個參數是一個回調函數,當前面指定的模塊都載入成功後,它將被調用。載入的模塊會以參數形式傳入該函數,從而在回調函數內部就可以使用這些模塊。

❸ js的模塊化編程有哪些方式

基礎

我們首先簡單地概述一下,自從三年前Eric Miraglia(YUI的開發者)第一次發表博客描述模塊化模式以來的一些模塊化模式。如果你已經對於這些模塊化模式非常熟悉了,大可以直接跳過本節,從「進階模式」開始閱讀。
匿名閉包
這是一種讓一切變為可能的基本結構,同時它也是Javascript最棒的特性。我們將簡單地創建一個匿名函數並立即執行它。所有的代碼將跑在這個函數內,生存在一個提供私有化的閉包中,它足以使得這些閉包中的變數能夠貫穿我們的應用的整個生命周期。

復制代碼 代碼如下:

(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());

注意這對包裹匿名函數的最外層括弧。因為Javascript的語言特性,這對括弧是必須的。在js中由關鍵詞function開頭的語句總是會被認為是函數聲明式。把這段代碼包裹在括弧中就可以讓解釋器知道這是個函數表達式。
全局變數導入
Javascript有一個特性叫做隱式全局變數。無論一個變數名在哪兒被用到了,解釋器會根據作用域鏈來反向找到這個變數的var聲明語句。如果沒有找到var聲明語句,那麼這個變數就會被視為全局變數。如果這個變數用在一句賦值語句中,同時這個變數又不存在時,就會創建出一個全局變數。這意味著在匿名閉包中使用或創建全局變數是很容易的。不幸的是,這會導致寫出的代碼極難維護,因為對於人的直觀感受來說,一眼根本分不清那些是全局的變數。
幸運的是,我們的匿名函數提供了簡單的變通方法。只要將全局變數作為參數傳遞到我們的匿名函數中,就可以得到比隱式全局變數更清晰又快速的代碼了。下面是示例:

復制代碼 代碼如下:

(function ($, YAHOO) {
// now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));

模塊導出
有時你不僅想要使用全局變數,你還想要聲明它們,以供反復使用。我們可以很容易地通過導出它們來做到這一點——通過匿名函數的返回值。這樣做將會完成一個基本的模塊化模式雛形,接下來會是一個完整的例子:

復制代碼 代碼如下:

var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moleProperty = 1;
my.moleMethod = function () {
// ...
};
return my;
}());

注意我們已經聲明了一個叫做MODULE的全局模塊,它擁有2個公有的屬性:一個叫做MODULE.moleMethod的方法和一個叫做MODULE.moleProperty的變數。另外,它還維護了一個利用匿名函數閉包的、私有的內置狀態。同時,我們可以很容易地導入需要的全局變數,並像之前我們所學到的那樣來使用這個模塊化模式。
進階模式
上面一節所描述的基礎已經足以應對許多情況,現在我們可以將這個模塊化模式進一步的發展,創建更多強大的、可擴展的結構。讓我們從MODULE模塊開始,一一介紹這些進階模式。
放大模式
整個模塊必須在一個文件中是模塊化模式的一個限制。任何一個參與大型項目的人都會明白將js拆分多個文件的價值。幸運的是,我們擁有一個很棒的實現來放大模塊。首先,我們導入一個模塊,並為它添加屬性,最後再導出它。下面是一個例子——從原本的MODULE中放大它:

復制代碼 代碼如下:

var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
};
return my;
}(MODULE));

我們用var關鍵詞來保證一致性,雖然它在此處不是必須的。在這段代碼執行完之後,我們的模塊就已經擁有了一個新的、叫做MODULE.anotherMethod的公有方法。這個放大文件也會維護它自己的私有內置狀態和導入的對象。
寬放大模式
我們的上面例子需要我們的初始化模塊最先被執行,然後放大模塊才能執行,當然有時這可能也不一定是必需的。Javascript應用可以做到的、用來提升性能的、最棒的事之一就是非同步執行腳本。我們可以創建靈活的多部分模塊並通過寬放大模式使它們可以以任意順序載入。每一個文件都需要按下面的結構組織:

復制代碼 代碼如下:

var MODULE = (function (my) {
// add capabilities...
return my;
}(MODULE || {}));

在這個模式中,var表達式使必需的。注意如果MODULE還未初始化過,這句導入語句會創建MODULE。這意味著你可以用一個像LABjs的工具來並行載入你所有的模塊文件,而不會被阻塞。
緊放大模式
寬放大模式非常不錯,但它也會給你的模塊帶來一些限制。最重要的是,你不能安全地覆蓋模塊的屬性。你也無法在初始化的時候,使用其他文件中的屬性(但你可以在運行的時候用)。緊放大模式包含了一個載入的順序序列,並且允許覆蓋屬性。這兒是一個簡單的例子(放大我們的原始MODULE):

復制代碼 代碼如下:

var MODULE = (function (my) {
var old_moleMethod = my.moleMethod;
my.moleMethod = function () {
// method override, has access to old through old_moleMethod...
};
return my;
}(MODULE));

我們在上面的例子中覆蓋了MODULE.moleMethod的實現,但在需要的時候,可以維護一個對原來方法的引用。
克隆與繼承

復制代碼 代碼如下:

var MODULE_TWO = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var super_moleMethod = old.moleMethod;
my.moleMethod = function () {
// override method on the clone, access to super through super_moleMethod
};
return my;
}(MODULE));

這個模式可能是最缺乏靈活性的一種選擇了。它確實使得代碼顯得很整潔,但那是用靈活性的代價換來的。正如我上面寫的這段代碼,如果某個屬性是對象或者函數,它將不會被復制,而是會成為這個對象或函數的第二個引用。修改了其中的某一個就會同時修改另一個(譯者註:因為它們根本就是一個啊!)。這可以通過遞歸克隆過程來解決這個對象克隆問題,但函數克隆可能無法解決,也許用eval可以解決吧。因此,我在這篇文章中講述這個方法僅僅是考慮到文章的完整性。
跨文件私有變數
把一個模塊分到多個文件中有一個重大的限制:每一個文件都維護了各自的私有變數,並且無法訪問到其他文件的私有變數。但這個問題是可以解決的。這里有一個維護跨文件私有變數的、寬放大模塊的例子:

復制代碼 代碼如下:

var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// permanent access to _private, _seal, and _unseal
return my;
}(MODULE || {}));

所有文件可以在它們各自的_private變數上設置屬性,並且它理解可以被其他文件訪問。一旦這個模塊載入完成,應用程序可以調用MODULE._seal()來防止外部對內部_private的調用。如果這個模塊需要被重新放大,在任何一個文件中的內部方法可以在載入新的文件前調用_unseal(),並在新文件執行好以後再次調用_seal()。我如今在工作中使用這種模式,而且我在其他地方還沒有見過這種方法。我覺得這是一種非常有用的模式,很值得就這個模式本身寫一篇文章。
子模塊
我們的最後一種進階模式是顯而易見最簡單的。創建子模塊有許多優秀的實例。這就像是創建一般的模塊一樣:

復制代碼 代碼如下:

MODULE.sub = (function () {
var my = {};
// ...
return my;
}());

雖然這看上去很簡單,但我覺得還是值得在這里提一提。子模塊擁有一切一般模塊的進階優勢,包括了放大模式和私有化狀態。

閱讀全文

與js的模塊化編程相關的資料

熱點內容
伺服器網卡有什麼好處 瀏覽:90
javasql格式化 瀏覽:599
小愛同學機器人的命令詞 瀏覽:971
檢驗signature的php示例代碼 瀏覽:161
android內錄 瀏覽:776
騰訊雲輕量應用伺服器服務商 瀏覽:176
平板app打不開怎麼回事 瀏覽:317
九號怎麼用app控制前後移動 瀏覽:617
pdf瀏覽器預覽 瀏覽:695
六一兒童節程序員爸爸 瀏覽:166
農村電視天線加密 瀏覽:903
freepdfword 瀏覽:752
程序員怎麼做舔狗 瀏覽:584
怎麼保養汽車空調壓縮機 瀏覽:756
黑客與逆向工程師的python編程之道 瀏覽:864
企業信息化pdf 瀏覽:57
如何給男孩子解壓 瀏覽:735
伺服器雲轉發源ip 瀏覽:29
電腦伺服器地址指的什麼 瀏覽:955
蘋果怎麼下載匯成銀行app 瀏覽:899