簡體   English   中英

對象文字或模塊化Javascript設計模式

[英]Object Literal or Modular Javascript Design Pattern

這可能已經被問過很多次了,我已經搜索過了,但到目前為止我讀到的所有答案都不是我正在尋找的。

我正在開發一個網站,其中包含顯示/隱藏的中等DOM元素,一些AJAX調用,以及其他可能的東西。 所以我將有兩個主要的腳本文件(HTML5 Boilerplate標准)

plugins.js // third party plugins here
site.js // all my site specific code here

以前我使用的是對象文字設計模式,所以我的site.js是這樣的:

var site = {
  version: '0.1',
  init: function() {
    site.registerEvents();
  },
  registerEvents: function() {
    $('.back-to-top').on('click', site.scrollToTop);
  },
  scrollToTop: function() {
    $('body').animate({scrollTop: 0}, 400);
  }
};

$(function() {
  site.init();
});

到目前為止這么好,它的可讀性很好,所有方法都是公開的(我有點像這樣,因為我可以直接通過Chrome Dev Tools測試它們)。 但是,我打算將網站的一些功能分解為更模塊化的風格,所以我希望在上面的代碼(或單獨的文件)中有這樣的東西:

site.auth = {
  init: function() {
    site.auth.doms.loginButton.on('click', site.auth.events.onLoginButtonClicked);
  },
  doms: {
    loginButton: $('.login'),
    registerButton: $('.register')
  },
  events: {
    onLoginButtonClicked: function() {
    }
  },
  fbLogin: function() {
  }
};

site.dashboard = {
};

site.quiz = {
};

// more modules

如您所見,它非常易讀。 但是有一個明顯的缺點,就是我必須編寫像site.auth.doms.loginButtonsite.auth.events.onLoginButtonClicked這樣的代碼。 突然間,它變得難以閱讀,只有功能越復雜,它才會越長。 然后我嘗試了模塊化模式:

var site = (function() {
  function init() {
    $('.back-to-top').on('click', scrollToTop);
    site.auth.init();
  }

  function scrollToTop() {
    $('body').animate({scrollTop: 0}, 400);
  }

  return {
    init: init
  }
})();

site.auth = (function() {
  var doms = {
    loginButton: $('.login'),
    registerButton: $('.register')
  };

  function init() {
    doms.loginButton.on('click', onLoginButtonClicked);
  }

  function onLoginButtonClicked() {

  }

  return {
    init: init
  }
})();

// more modules

正如你所看到的,那些長名稱已經消失了,但是我想我必須在site.init()函數中初始化所有其他模塊來構建它們嗎? 然后我必須記住返回其他模塊需要訪問的功能。 他們兩個都沒關系我想雖然有點麻煩,但總的來說,我是否采用了模塊化模式的更好的工作流程?

當然,正確的答案是:“它取決於”。

如果您對所有數據和所有方法完全沒問題,那么對於您網站的每個部分都是100%公開的,那么只要使用單個文字(或多個文字),如果需要,可以使用嵌套對象,假設您可以防止它變成一個巨大的代碼球。

如果你想要任何類型的私有狀態,它具有任何類型的持久性(即:每次運行函數時都不會重置),那么揭示模塊就很棒了。

那說:
根本不需要具有.init方法的揭示模塊。
如果您的模塊可以是自包含的,那么只需專注於導出您想要公開的內容。

為此,當我編寫團隊可能會查看的代碼時,我發現自己正在創建一個public_interface對象並返回它(您返回的匿名對象的命名版本)。

這樣做的好處是最小的,除了添加了一個理解,即需要公開的任何內容都需要附加到接口。

你目前使用它的方式:

var module = (function () { /* ... */ return {}; }());

module.submodule = (function () { /*...*/ return {}; }());

沒有比文字更好或更差,因為你可以輕松地做到這一點:

var module = {
    a : "",
    method : function () {},
    meta : { }
};

module.submodule = {
    a : "",
    method : function () {},
    meta : { }
};

在你找到一些對你不起作用的東西之前,先處理滿足你需求的東西。

就個人而言,我通常會將任何僅數據對象構建為文字:config-objects,來自其他連接的對象等等......

任何需要一兩種方法的簡單易受污染的對象,並且可以通過僅嵌套一層或兩層深度來構建,我也可以逐字構建(只要它不需要初始化)。

// ex:
var rectangle = {
    width  : 12,
    height : 24,
    area : 0,
    perimeter : 0,
    init_area : function () { this.area = this.width * this.height; return this; }, // buh...
    init_perimeter : function () { this.perimeter = (this.width * 2) + (this.height * 2); return this; } // double-buh...
}.init_area().init_perimeter();

如果我需要其中的幾個,也許我會做一個構造函數。
但是,如果我只需要這樣一個獨特的東西,那么這樣做會不會讓我感到頭疼:

var rectangle = (function (width, height) {
    var public_interface = {
        width  : width,
        height : height,
        area   : width * height,
        perimeter : (2 * width) + (2 * height)
    };
    return public_interface;
}(12, 24));

如果需要更高級的計算,我可以將任何額外的變量保密,並從內部處理它們。
如果我需要在對象中包含敏感數據,並且需要處理該數據的函數,那么我可以使用調用這些私有函數的公共函數,並返回結果,而不是提供訪問。

此外,如果我重構我的代碼,並決定在某一點重命名rectangle ,那么任何嵌套3或更深的函數(也指向rectangle都必須進行修改。
同樣,如果你正在構造你的方法,以便他們不需要直接詢問任何比this更遠的對象,那么你就不會有這個問題......

...但是如果你有一個看起來像這樣的界面:

MyApp.myServices.webService.send();

而且它期望找到:

MyApp.appData.user.tokens.latest;  // where personally, I might leave tokens in a closure

如果更改appData模塊的結構,則會在webService模塊中出現各種錯誤,直到找到對舊格式的每個引用,並將它們全部重命名。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM