[英]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.loginButton
和site.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.