How to pass a variable by value to an anonymous javascript function?
目标
我想动态地将事件处理程序分配给整个站点的页面上的某些div。
我的方法
我使用jQuery绑定匿名函数作为选定div事件的处理程序。
问题
代码迭代div名称和相关URL的数组。 div名称用于设置绑定目标,即将此事件处理程序附加到此div事件。
当事件处理程序成功绑定到每个div事件时,由这些事件处理程序触发的操作只会定位到数组中的最后一项。
所以我的想法是,如果用户将鼠标放在给定的div上,它应该为该div运行一个滑出动画。但是,鼠标悬停在div1(rangeTabAll)上会触发div4的滑出动画(rangeTabThm)。对于div 2,3等也是如此。顺序并不重要。更改数组元素,事件将始终以数组div4中的最后一个元素为目标。
我的代码 - (使用jQuery)
1 2 3 4 5 6 7 8 9 10 11 12 13 | var curTab, curDiv; var inlineRangeNavUrls=[['rangeTabAll','range_all.html'],['rangeTabRem','range_remedial.html'], ['rangeTabGym','range_gym.html'],['rangeTabThm','range_thermal.html']]; for (var i=0;i<inlineRangeNavUrls.length;i++) { curTab=(inlineRangeNavUrls[i][0]).toString(); curDiv='#' + curTab; if ($(curDiv).length) { $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} ); $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} ); } } |
我的理论
我要么没有看到一个令人眼花缭乱的语法错误或它的引用问题。
最初我有以下语句来设置curTab的值:
1 | curTab=inlineRangeNavUrls[i][0]; |
因此,当问题发生时,我认为当我改变(通过循环迭代)对curTab的引用时,我实际上将所有先前的匿名函数事件处理程序的引用更改为新的curTab值....这就是为什么事件处理程序始终以最后一个div为目标。
所以我真正需要做的是将curTab值传递给匿名函数事件处理程序而不是curTab对象引用。
所以我认为:
1 | curTab=(inlineRangeNavUrls[i][0]).toString(); |
会解决问题,但事实并非如此。同样的交易。所以很明显我错过了关于这个问题的一些关键,也许是非常基本的知识。谢谢。
您需要在循环的每次传递中创建一个新变量,以便它将在您为事件处理程序创建的闭包中捕获。
但是,仅将变量声明移动到循环中将无法实现此目的,因为JavaScript不会为任意块引入新范围。
强制引入新范围的一种简单方法是使用另一个匿名函数:
1 2 3 4 5 6 7 8 9 10 11 12 | for (var i=0;i<inlineRangeNavUrls.length;i++) { curDiv='#' + inlineRangeNavUrls[i][1]; if ($(curDiv).length) { (function(curTab) { $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} ); $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} ); })(inlineRangeNavUrls[i][0]); // pass as argument to anonymous function - this will introduce a new scope } } |
正如Jason建议的那样,你可以使用jQuery的内置
1 2 3 4 5 6 7 8 9 10 11 12 | for (var i=0;i<inlineRangeNavUrls.length;i++) { (function(curTab) // introduce a new scope { $('#' + inlineRangeNavUrls[i][1]) .hover( function(){showHideRangeSlidingTabs(curTab, true);}, function(){showHideRangeSlidingTabs(curTab, false);} ); // establish per-loop variable by passsing as argument to anonymous function })(inlineRangeNavUrls[i][0]); } |
这里发生的事情是你的无数函数正在形成一个闭包,并将它们的外部范围与它们结合起来。这意味着当你在anomymous函数中引用curTab时,当事件处理程序运行该函数时,它将在你的外部作用域中查找curTab的当前值。这将是你最后分配给curTab的任何东西。 (不是在绑定功能时分配的内容)
你需要做的是改变这个:
1 | $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} ); |
对此:
1 2 3 4 5 6 7 | $(curDiv).bind("mouseover", (function (mylocalvariable) { return function(){ showHideRangeSlidingTabs(mylocalvariable, true); } })(curTab) ); |
这会将curTab的值复制到外部函数的范围内,内部函数将使用它。这种复制发生在您将内部函数绑定到事件处理程序的同时,因此"mylocalvariable"反映了当时curTab的值。然后下一次循环,将创建一个带有新范围的新外部函数,并将curTab的下一个值复制到其中。
shog9的答案基本上完成了同样的事情,但他的代码更加严谨。
它有点复杂,但如果你想一想就有意义。关闭很奇怪。
编辑:oops,忘了返回内部函数。固定。
您可以将变量的值放入非现有标记中,稍后您可以从那里读取它们。此代码段是循环体的一部分:
1 2 3 | s = introduction.introductions[page * 6 + i][0]; //The variables content $('#intro_img_'+i).attr('tag' , s); //Store them in a tag named tag $('#intro_img_'+i).click( function() {introduction.selectTemplate(this, $(this).attr('tag'));} ); //retrieve the stored data |
我认为你让它变得比它需要的更复杂。如果你所做的只是在鼠标悬停/输出上分配滑动效果,那么用jquery尝试悬停效果。
1 2 3 4 5 | $("#mytab").hover(function(){ $(this).next("div").slideDown("fast");}, function(){ $(this).next("div").slideUp("fast"); }); |
如果您发布了完整的HTML,我可以告诉您具体的操作方法:)