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 ];
...
您在事件委托中使用了绑定到外部变量 handlerIdx
的 handler
变量,因此在退出 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);
}
我正在尝试创建一个插件,用于传递特定事件的处理函数。在下面的简单示例中,我有两个按钮。当我按下按钮 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 ];
...
您在事件委托中使用了绑定到外部变量 handlerIdx
的 handler
变量,因此在退出 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);
}