【问题标题】:Jquery closures in a loop循环中的Jquery闭包
【发布时间】:2015-01-28 13:47:30
【问题描述】:

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

但是,当我按下按钮 1 时,标签变为“按钮 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/

【问题讨论】:

  • 将您的函数表达式放在createHandlerFunction 中(以便返回),而不是在调用周围,它会起作用。
  • 有点题外话:你不应该使用for..in 来迭代数组。

标签: javascript jquery closures


【解决方案1】:

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

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

您在事件委托中使用handler 变量,该变量绑定到外部变量handlerIdx,因此在退出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

【讨论】:

    【解决方案2】:

    这是您更新后的工作小提琴: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 );
        });
    }
    

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

    【讨论】:

      猜你喜欢
      • 2018-12-26
      • 2010-09-26
      • 2014-10-10
      • 2011-01-12
      • 1970-01-01
      • 2018-06-10
      • 1970-01-01
      • 2012-12-15
      • 2021-10-27
      相关资源
      最近更新 更多