10-讨论
9.2.3 讨论
1.优点和缺点
本秘诀的标题已经指出,这种方法更快。你将始终在一个对象上而不是在 jQuery.cache 的多个条目上触发事件。
这种方法的缺点是每个人都需要知道事件处理程序对象(例子中的 jQuery.page ),才能绑定或者触发已知的事件。
如果你的目标是封装代码,这可能是个负面因素。[1]
封装的概念在面向对象编程中是高度强迫性的,因此你对这个因素要格外小心。
封装与jQuery编程的相关度总体来说没有那么高,因为jQuery不是面向对象的,大部分用户不太关注代码封装。但是这仍然值得注意。
2.使监听器具备实际功能
前面提到的监听器对象并不一定是除了 bind() 、 unbind() 和 trigger() 之外什么都没有的简单“哑”对象(据我们所知)。
这些对象实际上可以拥有方法和属性,使其更加实用。
唯一的问题是,如果有如下代码:
jQuery.page = jQuery({ number:1 });
要访问 number 属性,就必须这么做:
jQuery.page.number; // undefined
jQuery.page[0].number; // 1
这是jQuery对HTML节点和其他变量的处理方式。
但是不要对我失去信心!这个问题很容易解决。编写一个小插件:
(function( $ ){
// 这些方法将从jQuery.fn复制到原型
var copiedMethods = 'bind unbind one trigger triggerHandler'.split(' ');
// 空的构造器
function Listener(){
};
$.each(copiedMethods, function(i,name){
Listener.prototype[name] = $.fn[name];
});
// "jQuery.fn.each必须更换
Listener.prototype.each = function(fn) {
fn.call(this);
return this;
};
$.listener = function( data ){
return $.extend(new Listener(), data);
};
})( jQuery );
现在,可以创建具有所需的所有事件相关jQuery方法的对象,但是传递给 bind() 、 unbind() 等的函数作用域将是对象本身(例子中的 jQuery.page )。
注意,监听器对象并不拥有所有 jQuery 方法,而只有复制的那些方法。虽然可以添加更多方法,但是它们大部分都无法正常工作。那样做需要更复杂的实现;我们将坚持使用例子中的这些方法,它们能够满足我们对事件的需求。
既然有了这个小型的插件,就能:
jQuery.page = jQuery.listener({
title: 'Start',
changeTo: function( title ){
this.title = title;
this.trigger('change');
}
});
jQuery.page.changeTo('Inbox');
因为现在你能够从处理程序中使用 this 访问对象,所以没有必要向处理程序传递标题等参数值。相反,可以简单地使用 this.title 访问该值:
jQuery.page.bind('change', function(e){
jQuery('#text1').text( 'Page is ' + this.title );
});