1

I was playing with a fiddle earlier today while trying to answer a question and found a confusing thing. Being a JS newbie I am not being able to debug whats going wrong myself. I even tried to check the source0 of $.fn.show in jQuery source but couldn't figure out whats going wrong.

HTML:

<input type='text' id='dataBox'/>
<input type='button' value='toggle' id='toggleButton' />​

jQuery code:

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();
}); 

The problem is for some mistake that I did, is causing this line to execute infinite number of times obj.trigger('beforeShow');

and hence the alert in this block

 $('#dataBox').bind('beforeShow', function () {
    alert('beforeShow');
 });  

seems not to stop.

Irrespect of what I am trying to do or if this can be done any other way, can someone please explain what I am doing wrong here. I have been trying for several hours but couldn't figure out.

FIDDLE

4

3 に答える 3

2

このセクションを見てみましょう

    if(speed)    
        _oldShow.apply(obj, [speed,newCallback]);
    else    
        _oldShow.apply(obj, [newCallback]);

    });

_oldShow$.fn.show;は以前のように割り当てられ.apply()、配列としての引数と のコンテキストを設定する機能を使用して関数を呼び出しますthis(こちらをご覧ください)

そのため、関数の最後では、常に関数を再度呼び出すことになり、beforeShow が無限にトリガーされます。

于 2012-05-22T16:02:48.577 に答える
1

上記のコードの問題は、ある時点で jQuery が$.fn.showそれ自体の中で from を呼び出し、それが無限ループを作成することです。したがって、それを防ぐ適切な方法は、次のような引数チェックを行うことです。

 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 は何らかの理由でそうしているようです)。

働くフィドル

于 2012-05-29T17:00:25.837 に答える
1

表示機能コードを調べます(アラート中): http://jsfiddle.net/D9vP6/4/

引数を正規化するために、何らかの条件で自分自身を呼び出すように見えました。この関数を再定義すると、無限再帰が発生します。

このような動作を回避するには、コード内でこのすべての正規化を行い、特定の条件下でイベントをトリガーしないようにする必要があります。

于 2012-05-22T16:04:38.817 に答える