For循环不循环对象的值——对每个元素应用相同的处理程序

For loop doesn't loop values of an object - applies same handler to each element

本文关键字:循环 应用 处理 元素 程序 对象 For      更新时间:2023-09-26

我编写了一个函数,旨在提供一种创建右键单击(上下文)菜单的简便方法。很好,但是你作为点击处理程序传递给它的函数不会应用到正确的菜单项上。

调用该函数时,向它传递click事件和一个包含菜单项名称及其处理函数的对象文本,如下所示:

context.menu(e,{
    "Hello": function() {
        alert("Hi");
    },
    "World": function() {
        alert("Hello world!");
    },
});

假设,对象字面值在for循环中循环,并且每个处理程序函数应用于相应的菜单项。然而,似乎传入的第一个处理程序函数被应用于所有菜单项。

函数是这样的:

this.menu = function(e,options) {
    e.preventDefault();
    var x = e.clientX;
    var y = e.clientY;
    var id = math.floor(math.random()*8192);
    id = "menu-"+id;
    var menu = "<div class='menu-wrapper'></div>";
    menu = $(menu);
    menu.attr("id",id);
    var i = 0;
    for(var key in options) {
        var option = $("<span class='menu-item' id='menu-item-"+i+"'>"+key+"</span>");
        var fn = options[key];
        option.appendTo(menu);
        option.on("click",function() {
            // $(this).css("background","yellow"); - just a test, not needed any more
            fn.call();
        });
        i++;
    }
    menu.appendTo("body");
    menu.css({
        top: y,
        left: x,
    });
    $(document).click(function() {
        $("#"+id).remove();
    });
    $("#"+id).click(function(e) {
        e.stopPropagation();
    });
}

我如何改变这一点,以便在正确的地方应用处理程序?

实时JSFiddle演示

更新:

我试过添加代码(使用typeof(options[key]);,所以它检查你传递的函数的类型,但仍然没有运气。console.log也给了我正确的值,所以我不知道为什么它不循环。

这是一个常见的陷阱。JS没有块作用域——你的fn变量每次迭代都会被重写。试着把它包在闭包里。

this.menu = function(e,options) {
    e.preventDefault();
    var x = e.clientX;
    var y = e.clientY;
    var id = math.floor(math.random()*8192);
    id = "menu-"+id;
    var menu = "<div class='menu-wrapper'></div>";
    menu = $(menu);
    menu.attr("id",id);
    var i = 0;
    for(var key in options) {
        (function(key){ // start closure
            var option = $("<span class='menu-item' id='menu-item-"+i+"'>"+key+"</span>");
            var fn = options[key];
            option.appendTo(menu);
            option.on("click",function() {
                // $(this).css("background","yellow"); - just a test, not needed any more
                fn.call();
            });
        })(key); // end closure
        i++;
    }
    menu.appendTo("body");
    menu.css({
        top: y,
        left: x,
    });
    $(document).click(function() {
        $("#"+id).remove();
    });
    $("#"+id).click(function(e) {
        e.stopPropagation();
    });
}