jQuery 和闭包

发布于 2024-07-13 02:33:18 字数 1309 浏览 8 评论 0原文

我的页面上有多个菜单,它们都使用相同的鼠标悬停和单击事件,因此我决定将其放入一个函数中。 然而,变量似乎总是被分配给悬停(函数,函数)函数的最后一个参数。

$(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 将始终记录最后一个 active 而不是属于arguments[i].active 的日志。 (在此示例中,它始终记录参数[1].active 的 active) 我究竟做错了什么?

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

I have a multiple menu's on my page which all use the same mouseover and click events, so I decided to get it into a function. However vars seem to always be assigned to the last of the arguments for the hover(function, function) function.

$(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)'});
});

Why is is that the last console.log will always logs the last active instead of the one that belongs to arguments[i].active. (In this example it always logs the active of arguments[1].active)
What am I doing wrong?

Also, the real function is more complex, but the problem is also present in this variant.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

漫雪独思 2024-07-20 02:33:18

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
    }
}

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

JavaScript doesn't have block scope, so those variables you declare in the for loop have their values changed each iteration and all those functions reference the same variables. The trick is to create a new function scope within the for loop so that the variables you declare are bound during that iteration.

You can accomplish this by executing an anonymous function inside the loop:

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
    }
}

The way you had it before, all of you functions closed over the same variable references, and so used what ever the last value was, not the value of when the function was created. Using the function scope will have it behave as you intended.

辞取 2024-07-20 02:33:18

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

试试这个:

        $(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 元素内部,以便可以在范围内访问它。

Your problem is that the hover event occurs outside of the scope of your executing method. So by the time the hover executes your active variable has already gone through the entire set and rests at the active state of your last element. So you are seeing this problem because that last log is an event, which is out of scope, and the other two are in-scope in the loops.

Try this:

        $(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")));
            });

This will actually store the 'active' value inside of the DOM element so that it can be accessed in scope.

自由如风 2024-07-20 02:33:18

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

$("#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");
    });
});

I'm racking my brains because it's a weird issue but I refactored the function a bit, might be useful (oh, someone much cleverer answered in the meantime):

$("#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");
    });
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文