我正在尝试写'更好'的javascript。
以下是我发现的一种模式,我正在尝试采用。但是,我对它的使用感到有些困惑。
比如说,我有一个名为“Jobs”的页面。该页面上的任何JS功能都将封装在以下内容中:
window.jobs = (function(jobs, $, undefined){
return {
addNew: function(){
// job-adding code
}
}
})(window.jobs|| {}, jQuery);
$(function(){
$('.add_job').on('click', function(event){
event.preventDefault();
window.jobs.addNew();
});
});
正如你可以推断的那样,我所做的就是替换所有在匿名事件处理函数内部的代码,并调用我的全局作业对象中的函数。我不确定为什么这是一件好事,除了它减少了可变碰撞的可能性并使整个事情变得更整洁,但这对我来说已经足够了。
- 可能相当明显 - 问题是:我所有的事件绑定init类型的东西仍然位于我闪亮的新工作对象之外:它应该在哪里?在工作对象里面?在jobs对象里面的返回对象里面?在init()函数内部?
我只是试图了解一个稳定的,基本的框架,用于放置简单的功能。我不是在构建JS应用程序,我只是想编写一个比它更强大和可维护的代码。目前。热烈欢迎任何和所有建议:)
答案 0 :(得分:2)
您可以按照自己喜欢的modules
/ objects
来分解应用程序。
例如,您可以拥有另一个对象/模块来缓存和定义所有DOM节点,另一个对象/模块只处理任何事件。例如:
(function ( win, doc, $, undef ) {
win.myApp = win.myApp || { };
var eventHandler = {
onJobClick: function( event ) {
event.preventDefault();
myApp.addNew();
}
};
var nodes = (function() {
var rootNode = $( '.myRootNode' ),
addJob = rootNode.find( '.add_job' );
return {
rootNode: rootNode,
addJob: addJob
};
}());
$(function() {
myApp.nodes.addJob.on( 'click', myApp.handler.onJobClick );
});
myApp.nodes = nodes;
myApp.handler = eventHandler;
}( this, this.document, jQuery ));
如何在这个(模块)模式中创建单例并不重要,无论是文字,构造函数,Object.create()
还是诸如此类。它需要符合您的要求。
但你应该尝试创建与necesarry一样多的特定模块/对象。当然,如果将这些单例/模块/对象分成多个javascript文件并按需加载它们并且在你说刀之前更有意义,那么你就处于模块化编程模式的世界中,处理requireJS
和AMD或CommonJS模块。
答案 1 :(得分:1)
封装方面,你没关系:你甚至可以在jQuery闭包中声明addNew
,你仍然可以避开全局范围。我认为你所获得的更多是实现接近MVC架构的东西。
我喜欢做的是创建一个用DOM元素实例化的对象,它负责自己的绑定/提供访问其控件的方法等。
示例:
// (pretend we're inside a closure already)
var myObj = function(args){
this.el = args.el; // just a selector, e.g. #myId
this.html = args.html;
this.bindings = args.bindings || {};
}
myObj.prototype.appendTo = function(elem){
elem.innerHTML += this.html;
this.bindControls();
};
myObj.prototype.remove = function(){
$(this.el).remove(); // using jQuery
};
myObj.prototype.bindControls = function(){
for(var i in this.bindings){ // event#selector : function
var boundFunc = function(e){ return this.bindings[i].call(this,e); };
$(this.el).on(i,boundFunc);
}
};
答案 2 :(得分:1)
你现在正在这样做的方式也正如我所做的那样,我通常在匿名函数本身内创建窗口对象然后在其中声明(在这种情况下:jClass = window.jClass)。
(function (jClass, $, undefined) {
/// <param name="$" type="jQuery" />
var VERSION = '1.31';
UPDATED_DATE = '7/20/2012';
// Private Namespace Variables
var _self = jClass; // internal self-reference
jClass = window.jClass; // (fix for intellisense)
$ = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense)
// I init my namespace from inside itself
$(function () {
jClass.init('branchName');
});
jClass.init = function(branch) {
this._branch = branch;
this._globalFunctionality({ globalDatePicker: true });
this._jQueryValidateAdditions();
//put GLOBAL IMAGES to preload in the array
this._preloadImages( [''] );
this._log('*******************************************************');
this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE);
this._log('*******************************************************\n');
};
jClass._log = function() {
//NOTE: Global Log (cross browser Console.log - for Testing purposes)
//ENDNOTE
try { console.log.apply(console, arguments); }
catch (e) {
try { opera.postError.apply(opera, arguments); }
catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ }
}
};
}(window.jClass= window.jClass|| {}, jQuery));
我这样完全匿名的原因是,让我们在另一个文件中说我想为这个jClass添加更多功能。我只想创建另一个:
(function jClass, $, undefined) {
jClass.newFunction = function (params) {
// new stuff here
};
}(window.jClass = window.jClass || {}, jQuery))
正如你所看到的,我更喜欢object.object表示法,但你可以使用对象文字对象:对象,这取决于你!
通过将所有这些分开,并且没有实际页面逻辑进行封装,可以更容易地在globalJS文件中使用它,并且站点上的每个页面都可以使用它。如下例。
jClass._log('log this text for me');
您不希望将模型逻辑与业务逻辑交织在一起,因此您在正确的路径上将两者分开,并允许您的全局命名空间/类/等更灵活!
答案 3 :(得分:0)
您可以在此处找到有关模块模式的全面研究:http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html它涵盖了块范围模块方法的所有方面。但是在实践中你会有很多文件封装你的代码,所以问题是如何将它们组合起来。 AMD ...每个模块加载产生的多个HTTP请求都会损害您的页面响应时间。因此,您可以将CommonJS编译为适合浏览器使用的单个JavaScript文件。看看它是多么容易http://dsheiko.github.io/cjsc/