代码之家  ›  专栏  ›  技术社区  ›  Pim Jager

jQuery和闭包

  •  1
  • Pim Jager  · 技术社区  · 16 年前

    我的页面上有多个菜单,它们都使用相同的鼠标悬停和点击事件,所以我决定把它放到一个函数中。然而,var似乎总是被分配给hover(函数,函数)函数的最后一个参数。

    $(document).ready( function() {
    menuMouseOver = function() {
        for(i=0, u=arguments.length; i<u; i++){
            var parent = arguments[i].parent;
            var active = arguments[i].active;
            var childSelect = arguments[i].childSelect;
            console.log(active); //logs the correct active
                $(parent).children(childSelect)
                    .not('.'+active).each( function(i, e) {console.log(active);})
     //The above console.log logs the correct active 
                        .hover( function() {
                                console.log(active); //this one always logs menu2_active
                                $(this).addClass(active);
                            }, function() {
                                $(this).removeClass(active);
                            });
        }
    }
    menuMouseOver( { parent: '#menu1',
                    active: 'menu1_active',
                    childSelect: ':gt(0)'},
                { parent: '#menu2',
                    active: 'menu2_active',
                    childSelect: ':gt(0)'});
    });
    

    为什么最后一个console.log总是记录最后一个 积极的 而不是属于论点的论点[i]。活跃的。(在这个例子中,它总是记录 积极的 论点[1]。活跃) 我做错了什么?

    此外,实际函数更复杂,但这个变体中也存在问题。

    3 回复  |  直到 16 年前
        1
  •  4
  •   Zach    16 年前

    JavaScript没有块作用域,所以你在for循环中声明的那些变量每次迭代都会改变它们的值,所有这些函数都引用相同的变量。诀窍是在for循环中创建一个新的函数作用域,以便在迭代过程中绑定您声明的变量。

    你可以通过在循环中执行匿名函数来实现这一点:

    menuMouseOver = function() {
        for(i=0, u=arguments.length; i<u; i++){
          (function(){ // anonymous function to create new scope
            var parent = arguments[i].parent;
            var active = arguments[i].active;
            var childSelect = arguments[i].childSelect;
            console.log(active); //logs the correct active
                $(parent).children(childSelect)
                    .not('.'+active).each( function(i, e) {console.log(active);})
     //The above console.log logs the correct active 
                        .hover( function() {
                                console.log(active); //this one always logs menu2_active
                                $(this).addClass(active);
                            }, function() {
                                $(this).removeClass(active);
                            });
           })(); // execute the anonymous function
        }
    }
    

    按照以前的方式,所有函数都在相同的变量引用上关闭,因此使用最后一个值,而不是创建函数时的值。使用函数作用域将使其按预期运行。

        2
  •  1
  •   Nick Berardi    16 年前

    你的问题是 悬停事件 发生在执行方法的范围之外。因此,当悬停执行您的 积极的 变量已经遍历了整个集合,并处于最后一个元素的活动状态。所以你看到这个问题是因为最后一个日志是一个事件,它超出了范围,而另外两个在循环中在范围内。

    试试这个:

            $(parent).children(childSelect)
                .not('.'+active).each( function(i, e) {
                    console.log(active);
                    $(this).data("active", active);
                })
                .hover( function() {
                    $(this).addClass($(this).data("active"));
                }, function() {
                    $(this).removeClass($(this).data("active")));
                });
    

    这实际上会将“active”值存储在DOM元素中,以便在作用域中访问它。

        3
  •  0
  •   roborourke    16 年前

    我绞尽脑汁,因为这是一个奇怪的问题,但我稍微重构了这个函数,可能会有用(哦,与此同时,有更聪明的人回答了):

    $("#menu1,#menu2").each(function(){
        var id = $(this).attr("id");
        $(">li",this).not("."+id+"_active,:eq(0)").hover(function(){
            $(this).addClass(id+"_active");
        },function(){
            $(this).removeClass(id+"_active");
        });
    });