今天早些时候我正在玩弄小提琴,试图回答一个问题并发现一个令人困惑的事情。作为一个JS新手,我无法调试自己出错了什么。我甚至试图在jQuery源代码中检查$.fn.show
的source0但是无法弄清楚什么是错误的。
HTML:
<input type='text' id='dataBox'/>
<input type='button' value='toggle' id='toggleButton' />
jQuery代码:
jQuery(function ($) {
var _oldShow = $.fn.show;
$.fn.show = function (speed, oldCallback) {
return $(this).each(function () {
var obj = $(this),
newCallback = function () {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
obj.trigger('beforeShow');
if(speed)
_oldShow.apply(obj, [speed,newCallback]);
else
_oldShow.apply(obj, [newCallback]);
});
}
});
$('#dataBox').bind('beforeShow', function () {
alert('beforeShow');
});
$('#toggleButton').click(function(){
$('#dataBox').show();
});
问题在于我做了一些错误,导致这一行无限次执行 obj.trigger( 'beforeShow');
因此此块中的alert
$('#dataBox').bind('beforeShow', function () {
alert('beforeShow');
});
似乎没有停止。
不知道我想做什么,或者如果可以通过其他任何方式做到这一点,有人可以解释我在这里做错了什么。我已经尝试了几个小时,但无法弄明白。
答案 0 :(得分:2)
让我们来看看这一节
if(speed)
_oldShow.apply(obj, [speed,newCallback]);
else
_oldShow.apply(obj, [newCallback]);
});
_oldShow
之前被$.fn.show;
指定为.apply()
,this
调用带参数的函数作为数组,并能够设置{{1}}的上下文。 (see here)
因此,在函数结束时,我们总是最终再次调用函数,在beforeShow之前无限触发。
答案 1 :(得分:1)
查看show function code(在警报中): http://jsfiddle.net/D9vP6/4/
为了规范论证,似乎在某种条件下打电话给自己。重新定义此函数后,您将收到无限递归。
为避免此类行为,您应该在代码中进行所有这些规范化,并且在某些情况下不要触发事件。
答案 2 :(得分:1)
上面代码的问题在于,jQuery在某些时候从内部调用$.fn.show
并创建无限循环。因此,防止这种情况的正确方法是进行一些参数检查,如下所示:
jQuery(function($) {
var _oldShow = $.fn.show;
$.fn.show = function(speed, easing, oldCallback) {
var args = Array.prototype.slice.call(arguments),
duration = args[0] || 0,
easing = 'linear',
callback = function() {},
callbackArgIndex = 1;
// jQuery recursively calls show sometimes; we shouldn't
// handle such situations. Pass it to original show method.
if (!this.selector) {
_oldShow.apply(this, args);
return this;
}
if (args.length === 2) {
if ($.isFunction(args[1])) {
callback = args[1];
callbackArgIndex = 1;
}
else {
easing = args[1];
}
}
else if (args.length === 3) {
easing = args[1];
callback = args[2];
callbackArgIndex = 2;
}
return this.each(function() {
var obj = $(this),
oldCallback = callback,
newCallback = function() {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
obj.trigger('beforeShow');
args[0] = duration;
if (callback) {
args[callbackArgIndex] = newCallback;
}
else {
args.push(callback);
}
_oldShow.apply(obj, args);
});
}
});
$('#dataBox').bind('beforeShow afterShow', function(e) {
alert(e.type);
});
$('#toggleButton').click(function() {
$('#dataBox').show();
});
这样可以正常工作并且事件被正确解雇。
阻止无限循环的块是
if (!this.selector) {
_oldShow.apply(this, args);
return this;
}
这是做什么的,调用原始函数并在jQuery多次调用$.fn.show
的情况下返回(jQuery似乎出于某种原因这样做)。