我在一个网站上使用适度的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开发工具直接测试他们,如果需要).然而,我打算将网站的某些功能分解为更多的模块化样式,所以我想在上面的代码(或单独的文件)中有类似的东西:
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 : "",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));
如果有更高级的计算需要,我可以保留任何额外的vars私人,并从里面工作.
如果我需要在一个对象内部具有敏感数据,并且可以对该数据进行处理,那么我可以使用调用这些私有函数的公共函数,并返回结果,而不是提供访问.
此外,如果我重构我的代码,并且决定在某个时候重命名矩形,那么嵌套3或更深的任何函数,即指向矩形也必须被修改.
再次,如果你正在构造你的方法,使他们不需要直接询问任何比这更远的对象,那么你不会有这个问题?
…但是如果你有一个界面看起来像:
MyApp.myServices.webService.send();
并期待找到:
MyApp.appData.user.tokens.latest; // where personally,I might leave tokens in a closure
如果您更改了AppData模块的结构,您将在WebService模块中出现各种错误,直到找到对旧格式的所有引用,并重命名它们.