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

JavaScript架構設計Module模式用法實例詳解

伊谢尔伦
發布: 2017-07-24 13:50:46
原創
2157 人瀏覽過

module模式是一個比較流行的設計模式,它可以透過大括號封裝私有的變量,方法,狀態的,透過包裝這些內容,一般全局的物件不能直接訪問,在這個設計模式裡,只回傳一個API,其它的內容全部被封裝成私有的了。

另外,這個模式和自執行的函數表達式比較相似,唯一的差異是module回傳的是對象,而自執行函數表達式回傳的是function。

眾所周知, JavaScript不想其它語言一樣有存取修飾符,不能為每個欄位或方法宣告private,public修飾符,那這個模式我們是如何實現的呢?那就是return一個對象,裡麵包括一些公開的方法,這些方法有能力去呼叫內部的對象。

看一下,下面的程式碼,這段程式碼是一個自執行程式碼,宣告裡包含了一個全域的物件basketModule, basket數組是一個私有的,所以你的整個程式是不能存取這個私有數組的,同時我們return了一個對象,其內包含了3個方法(例如addItem,getItemCount,getTotal),這3個方法可以存取私有的basket數組。


var basketModule = (function() {
var basket = []; //private
return { //exposed to public
  addItem: function(values) {
    basket.push(values);
  },
  getItemCount: function() {
    return basket.length;
  },
  getTotal: function(){
    var q = this.getItemCount(),p=0;
    while(q--){
    p+= basket[q].price;
    }
    return p;
  }
 }
}());
登入後複製

同時注意,我們return的物件直接賦值給了basketModule,所以我們可以像下面一樣使用:


//basketModule is an object with properties which can also be methods
basketModule.addItem({item:'bread',price:0.5});
basketModule.addItem({item:'butter',price:0.3});
 
console.log(basketModule.getItemCount());
console.log(basketModule.getTotal());
 
//however, the following will not work:
console.log(basketModule.basket);// (undefined as not inside the returned object)
console.log(basket); //(only exists within the scope of the closure)
登入後複製

那在各個流行的類別庫(如Dojo, jQuery)裡是如何來做呢?

Dojo

Dojo試圖使用dojo.declare來提供class風格的宣告方式,我們可以利用它來實現Module模式,例如如果你想再store命名空間下宣告basket對象,那麼可以這麼做:


//traditional way
var store = window.store || {};
store.basket = store.basket || {};
 
//using dojo.setObject
dojo.setObject("store.basket.object", (function() {
  var basket = [];
  function privateMethod() {
    console.log(basket);
  }
  return {
    publicMethod: function(){
      privateMethod();
    }
   };
}()));
登入後複製

結合dojo.provide一起來使用,非常強大。

YUI

下面的程式碼是YUI原始的實作方式:


##

YAHOO.store.basket = function () {

 //"private" variables:
 var myPrivateVar = "I can be accessed only within YAHOO.store.basket .";

 //"private" method:
 var myPrivateMethod = function () {
 YAHOO.log("I can be accessed only from within YAHOO.store.basket");
 }

 return {
 myPublicProperty: "I'm a public property.",
 myPublicMethod: function () {
  YAHOO.log("I'm a public method.");

  //Within basket, I can access "private" vars and methods:
  YAHOO.log(myPrivateVar);
  YAHOO.log(myPrivateMethod());

  //The native scope of myPublicMethod is store so we can
  //access public members using "this":
  YAHOO.log(this.myPublicProperty);
 }
 };

} ();
登入後複製

jQuery

jQuery裡有很多Module模式的實現,我們來看一個不同的例子,一個library函數宣告了一個新的library,然後創建該library的時候,在document.ready裡自動執行init方法。


function library(module) {
  $(function() {
    if (module.init) {
      module.init();
    }
  });
  return module;
}
 
var myLibrary = library(function() {
  return {
    init: function() {
      /*implementation*/
      }
  };
}());
登入後複製

物件自面量

#物件自面量使用大括號聲明,而且使用的時候不需要使用new關鍵字,如果對一個模組裡的屬性欄位的publice/private不是很在意的話,可以使用這種方式,不過請注意這種方式和JSON的不同。物件自面量:var item={name: "tom", value:123} JSON:var item={"name":"tom", "value":123}。


var myModule = {
 myProperty: 'someValue',
 //object literals can contain properties and methods.
 //here, another object is defined for configuration
 //purposes:
 myConfig: {
 useCaching: true,
 language: 'en'
 },
 //a very basic method
 myMethod: function () {
 console.log('I can haz functionality?');
 },
 //output a value based on current configuration
 myMethod2: function () {
 console.log('Caching is:' + (this.myConfig.useCaching) ? 'enabled' : 'disabled');
 },
 //override the current configuration
 myMethod3: function (newConfig) {
 if (typeof newConfig == 'object') {
  this.myConfig = newConfig;
  console.log(this.myConfig.language);
 }
 }
};

 
myModule.myMethod(); //I can haz functionality
myModule.myMethod2(); //outputs enabled
myModule.myMethod3({ language: 'fr', useCaching: false }); //fr
登入後複製

CommonJS

#關於CommonJS的介紹,這裡就不多說了,之前很多文章都有介紹,我們這裡要提一下的是CommonJS標準裡有2個重要的參數exports和require,exports是代表要載入的模組,require是代表這些載入的模組需要依賴它的模組,也需要將它加載進來。


/*
Example of achieving compatibility with AMD and standard CommonJS by putting boilerplate around the standard CommonJS module format:
*/
 
(function(define){
  define(function(require,exports){
    // module contents
    var dep1 = require("dep1");
    exports.someExportedFunction = function(){...};
    //...
  });
})(typeof define=="function"?define:function(factory){factory(require,exports)});
登入後複製

有很多CommonJS標準的模組加載實現,我比較喜歡的是RequireJS,它能否非常好的加載模組以及相關的依賴模組,來一個簡單的例子,例如需要將圖片轉換成ASCII碼,我們先載入encoder模組,然後取得他的encodeToASCII方法,理論上程式碼應該是如下:


var encodeToASCII = require("encoder").encodeToASCII;
exports.encodeSomeSource = function(){
  //其它操作以后,然后调用encodeToASCII
}
登入後複製

但是上述程式碼並沒用,因為encodeToASCII函數並沒用附加到window物件上,所以不能使用,改進以後的程式碼需要這樣才行:


define(function(require, exports, module) {
  var encodeToASCII = require("encoder").encodeToASCII;
    exports.encodeSomeSource = function(){
    //process then call encodeToASCII
  }
});
登入後複製

以上是JavaScript架構設計Module模式用法實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板