Jquery 循环中的闭包

Jquery closures in a loop

我正在尝试创建一个插件,用于传递特定事件的处理函数。在下面的简单示例中,我有两个按钮。当我按下按钮 1 时,其标签应更改为 'Button A',而当我按下按钮 2 时,其标签应更改为 'Button B'。

但是,当我按下按钮 1 时,标签变为 'Button B'。我知道这与循环中的处理函数闭包有关,但我不知道如何解决它。

<body>
    <button class="btn1">Button 1</button>
    <button class="btn2">Button 2</button>
</body>    

这是我的 jquery:

$(function() {

    $("body").myplugin( {
        helperFunctions : {
            funcA : function( obj ) {
                $(obj).text( "Button A" );
            },

            funcB : function( obj ) {
                $(obj).text( "Button B" );
            }
        },

        handlers : [
            {   
             on : "click",
             selector : ".btn1",
             handlerFunc : function( funcs, obj ){
                               funcs.funcA( obj );
                           }

            },

            {   
             on : "click",
             selector : ".btn2",
             handlerFunc : function( funcs, obj ){
                               funcs.funcB( obj );
                           }

            }
        ]
    });

});


(function ($) {
    $.fn.extend({
        myplugin: function ( settings ) {
            var $this = $(this);

            function createHandlerFunction( func, obj ){
                return func( settings.helperFunctions, obj ) ;
            }

            for( var handlerIdx in settings.handlers ){
                var handler = settings.handlers[ handlerIdx ];
                $this.on(  
                     handler.on, 
                     handler.selector, 
                     function() { 
                         return createHandlerFunction( handler.handlerFunc, this ) } );
                     }
            }
    });
})(jQuery);

抱歉,示例有点长。这里是 http://jsfiddle.net/30nL07db/

这是您更新后的工作 fiddle:http://jsfiddle.net/30nL07db/42/

for( var handlerIdx in settings.handlers ){
    var handler = settings.handlers[ handlerIdx ];
    $this.on(handler.on, handler.selector, handler, function(event) {
        return createHandlerFunction( event.data.handlerFunc, this );
    });
}

只需将处理程序作为数据参数传递给事件注册,否则变量处理程序将指向其最后分配的值(即循环的最后一个值);

所以您的代码中的问题在于:

for( var handlerIdx in settings.handlers ){
    var handler = settings.handlers[ handlerIdx ];
...

您在事件委托中使用了绑定到外部变量 handlerIdxhandler 变量,因此在退出 for 循环时,handlerIdx 将是最后一个 id.. .

这是一个有 3 个 ID 的反例:see fiddle

查看关于闭包的其他问题:here

关于闭包的教程:here

所以让我们创建一个函数来创建事件委托,在循环外,在循环内只传递该函数,就像这样:

function createEvent(id) {
    $this.on(
      settings.handlers[id].on,
      settings.handlers[id].selector,
      function() {
         settings.handlers[id].handlerFunc( settings.helperFunctions, this)
      }
    );
}

 for( var handlerIdx in settings.handlers ){
     var handler = settings.handlers[ handlerIdx ];
     var s = handler.selector;
     createEvent(handlerIdx);
 }

See fiddle with this answer, working as you expect