首頁 > web前端 > js教程 > 主體

深入分析JavaScript的Module模式編程

coldplay.xixi
發布: 2020-07-29 17:32:28
轉載
2985 人瀏覽過

深入分析JavaScript的Module模式編程

基礎

#首先我們要大概了解Module模式(2007年由YUI的EricMiraglia在部落格中提出),如果你已熟悉Module 模式,可以跳過本部分,直接閱讀"高級模式"。

相關學習推薦:javascript影片教學

#匿名函數閉包

##「匿名函數閉套件是JavaScript最棒的特徵,沒有之一,是它讓一切都成為了可能。現在我們來建立一個匿名函數然後立即執行。函數中所有的程式碼都是在一個閉包中執行的,閉包決定了在整個執行過程中這些程式碼的私有性和狀態。

程式碼如下:

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

注意在匿名函數外面的括號。這是由於在JavaScript中以function開頭的語句通常被認為是函數宣告。加上了外面的括號之後則是建立的是函數表達式。

全域導入

JavaScript有一個特徵叫做隱藏的全域變數。當一個變數名被使用,編譯器會向上級查詢用var來宣告這個變數的語句。如果沒有找到的話這個變數就被認為是全域的。如果在賦值的時候這樣使用,就會創造一個全域的作用域。這意味著在一個匿名的閉包中建立一個全域變數是十分容易的。不幸的是 ,這將會導致程式碼的難以管理,因為對於程式設計師來說,如果全域的變數不是在一個檔案中聲明會很不清晰。幸運的是 ,匿名函數給我我們另一個選擇。我們可以將全域變數透過匿名函數的參數來匯入到我們的程式碼中,這樣更加的快速和整潔。

程式碼如下:


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

Module匯出

有時你不想要使用全域變量,但是你想要宣告他們。我們可以很容易地透過匿名函數的返回值來導出他們。關於Module模式的基本內容就這麼多,這裡有一個複雜一點的例子。

程式碼如下:

var MODULE = (function () {
 var my = {},
  privateVariable = 1;
 function privateMethod() {
  // ...
 }
 my.moduleProperty = 1;
 my.moduleMethod = function () {
  // ...
 };
 return my;
}());
登入後複製

這裡我們宣告了一個全域的module叫做MODULE,有兩個公有屬性:一個叫做MODULE.moduleMethod的方法和一個叫做MODULE.moduleProperty的變數。另外他透過匿名函數的閉包來維持私有的內部狀態,當然我們也可使用前面提到的模式,輕鬆匯入所需的全域變數

進階模式

之前提到的內容已經可以滿足很多需求了,但我們可以更深入地研究這種模式來創造一些強力的可拓展的結構。讓我們一點一點,繼續透過這個叫做MODULE的module來學習。

拓展

目前,module模式的一個限制就是整個module必須是寫在一個檔案裡面的。每個進行過大規模程式碼開發的人都知道將一個檔案分離成多個檔案的重要性。幸運的是我們有一個很好的方式來拓展modules。首先我們導入一個module,然後加屬性,最後將它匯出。這裡的這個例子,就是用上面所說的方法來拓展MODULE。

程式碼如下:


var MODULE = (function (my) {
 my.anotherMethod = function () {
  // added method...
 };
 return my;
}(MODULE));
登入後複製

雖然不必要,但是為了一致性 ,我們再次使用var關鍵字。然後程式碼執行,module會增加一個叫做MODULE.anotherMethod的公有方法。這個拓展文件同樣也維持著它私有的內部狀態和導入。

松拓展

我們上面的例子需要我們先建立module,然後在對module進行拓展,這並不是必須的。非同步載入腳本是提升 Javascript 應用效能的最佳方式之一。 。透過松拓展,我們創建靈活的,可以以任意順序加載的,分成多個檔案的module。每個檔案的結構大致如下

程式碼如下:


var MODULE = (function (my) {
 // add capabilities...
 return my;
}(MODULE || {}));
登入後複製

在這個模式下,var語句是必須。如果導入的module不存在就會被創建。這意味著你可以用類似LABjs的工具來並行載入這些module的檔案。

緊拓展

雖然松拓展已經很棒了,但它也為你的module增添了一些限制。最重要的一點是,你沒有辦法安全的重寫module的屬性,在初始化的時候你也不能使用其他檔案中的module屬性(但你可以在初始化之後運行)。緊拓展包含了一定的載入順序,但支援重寫,以下是一個例子(拓展了我們最初的MODULE)。

程式碼如下:


var MODULE = (function (my) {
 var old_moduleMethod = my.moduleMethod;
 my.moduleMethod = function () {
  // method override, has access to old through old_moduleMethod...
 };
 return my;
}(MODULE));
登入後複製

這裡我們已經重寫了MODULE.moduleMethod,也依照需求保留了原始方法的參考。

複製與繼承

程式碼如下:


#

var MODULE_TWO = (function (old) {
 var my = {},
  key;
 for (key in old) {
  if (old.hasOwnProperty(key)) {
   my[key] = old[key];
  }
 }
 var super_moduleMethod = old.moduleMethod;
 my.moduleMethod = function () {
  // override method on the clone, access to super through super_moduleMethod
 };
 return my;
}(MODULE));
登入後複製

这种模式可能是最不灵活的选择。虽然它支持了一些优雅的合并,但是代价是牺牲了灵巧性。在我们写的代码中,那些类型是对象或者函数的属性不会被复制,只会以一个对象的两份引用的形式存在。一个改变,另外一个也改变。对于对象来说[g5] ,我们可以通过一个递归的克隆操作来解决,但是对于函数是没有办法的,除了eval。然而,为了完整性我还是包含了它。

跨文件的私有状态

把一个module分成多个文件有一很大的局限,就是每一个文件都在维持自身的私有状态,而且没有办法来获得其他文件的私有状态。这个是可以解决的,下面这个松拓展的例子,可以在不同文件中维持私有状态。

代码如下:

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加载完毕,程序会调用MODULE._seal(),让外部没有办法接触到内部的 _.private。如果之后module要再次拓展,某一个属性要改变。在载入新文件前,每一个文件都可以调用_.unsea(),,在代码执行之后再调用_.seal。

这个模式在我今天的工作中想到的,我从没有在其他地方见到过。但是我认为这是一个很有用的模式,值得单独写出来。

Sub-modules

最后一个高级模式实际上是最简单的,有很多创建子module的例子,就像创建一般的module一样的。

代码如下:

MODULE.sub = (function () 
{ var my = {}; //
    ...
 return my;}());
登入後複製

虽然这可能是很简单的,但是我决定这值得被写进来。子module有一般的module所有优质的特性,包括拓展和私有状态。

总结

大多数高级模式都可以互相组合来创建更有用的新模式。如果一定要让我提出一个设计复杂应用的方法的话,我会结合松拓展,私有状态,和子module。

在这里我没有提到性能相关的事情,但是我可以说,module模式对于性能的提升有好处。它可以减少代码量,这就使得代码的载入更迅速。松拓展使得并行加载成为可能,这同样提升的载入速度。初始化的时间可能比其他的方法时间长,但是这多花的时间是值得的。只要全局变量被正确导入了运行的时候就不会出问题,在子module中由于对变量的引用链变短了可能也会提升速度。

最后,这是一个子module自身动态加载的例子(如果不存在就创建),为了简介我没有考虑内部状态,但是即便考虑它也很简单。这个模式可以让复杂,多层次的代码并行的加载,包括子module和其他所有的东西。

代码如下:

var UTIL = (function (parent, $) {
 var my = parent.ajax = parent.ajax || {};
 my.get = function (url, params, callback) {
  // ok, so I'm cheating a bit 
  return $.getJSON(url, params, callback);
 };
 // etc...
 return parent;
}(UTIL || {}, jQuery));
登入後複製

我希望这些内容是有用的,请在下面留言来分享你的想法。少年们,努力吧,写出更好的,更模块化的JavaScript。

以上是深入分析JavaScript的Module模式編程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:jb51.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!