分配单击侦听器时出现意外的范围问题

时间:2015-05-01 08:10:11

标签: javascript jquery scope

当我的loadNav()函数循环遍历nav数组并为动态创建的元素分配单击侦听器时,一切似乎都很好。如果break的第一个循环中的navItem.id'newGL',则第二次'litGL''litGL',应该如此。

但是当我在完成循环后检查侦听器时,它们都具有 'b' 的id(以及navItem.text的类型)。但是元素本身具有正确的.click,所以我想我不理解变量在传递函数中如何分配给var nav = [ { id:'newGL', text:'new', type:'a' }, { id:'litGL', text:'lit', type:'b' } ] function loadNav(nav){ for(item in nav){ var navItem = nav[item]; var element = $("<div>" + navItem.text + "</div>"); element.click(function(){ getContent(navItem.id,navItem.type); //in practice I'm getting two click listeners with a navItem.id of 'litGL' and a navItem.type of 'b' }); $('#horzNav').append(element); } } 方法。

为什么我的第一次点击监听器被第二个值覆盖的任何提示?

Code package linkedlist;

import java.util.Scanner;

/**
 *
 * @author Spock-II
 */
public class LinkedList {

    public static LinkedInt Trueadd(LinkedInt A, LinkedInt B) {
        LinkedInt a = A;
        LinkedInt b = B;

        int next;
        LinkedInt sum = new LinkedInt();

        System.out.println("Switches!");
        if (a.size() > b.size()) {
            System.out.println("size: " + (a.size() - b.size()));
            int limit = a.size() - b.size();
            for (int i = 0; i < limit; i++) {
                b.addToLinkList("0", i);
                System.out.println("inloop b");
                System.out.println("i : " + i);
            }
            System.out.println("loop complete");
        } else if (a.size() < b.size()) {
            System.out.println("size: " + (b.size() - a.size()));
            int limit = b.size() - a.size();
            for (int i = 0; i < limit; i++) {
                a.addToLinkList("0", i);
                System.out.println("inloop b");
                System.out.println("i : " + i);

            }
            System.out.println("loop complete");
        }

        System.out.println("Switch overcame");


        int carryover = 0;
        while (a.head != null & b.head != null) {
            String[] carryCheck = (Integer.valueOf(a.head.getItem()) + Integer.valueOf(b.head.getItem()) + "").split("");
            if (carryCheck.length == 2) {


                sum.addToLinkList((Integer.valueOf(carryCheck[1])+carryover)+"", 0);
                carryover = Integer.valueOf(carryCheck[0]);
            } else {
                int i = Integer.valueOf(a.head.getItem()) + Integer.valueOf(b.head.getItem());
                sum.addToLinkList(i + "", 0);
            }

            System.out.println("a: " + a.head.getItem());
            System.out.println("b: " + b.head.getItem());
            a.head = a.head.getLink();
            b.head = b.head.getLink();
        }
        System.out.println("Completed");
        return sum;

    }

    public static LinkedInt subtract(LinkedInt a, LinkedInt b) {
        a.combine();
        b.combine();
        LinkedInt difference = new LinkedInt(a.x - b.x);
        difference.combine();
        return difference;

    }

    public static LinkedInt multiply(LinkedInt a, LinkedInt b) {
        a.combine();
        b.combine();
        LinkedInt product = new LinkedInt(a.x + b.x);
        product.combine();
        return product;

    }

    public static LinkedInt divide(LinkedInt a, LinkedInt b) {
        a.combine();
        b.combine();
        LinkedInt sum = new LinkedInt(a.x + b.x);
        sum.combine();
        return sum;

    }

    public static LinkedInt modulus(LinkedInt a, LinkedInt b) {
        a.combine();
        b.combine();
        LinkedInt rem = new LinkedInt(a.x + b.x);
        rem.combine();
        return rem;

    }

    public static void main(String[] args) {
        // TODO code application logic here
        Scanner i1 = new Scanner(System.in);
        System.out.print("Please enter the first no. : ");
        int a = i1.nextInt();
        Scanner i2 = new Scanner(System.in);
        System.out.print("Please enter the second no. : ");
        int b = i2.nextInt();
        System.out.println();

        LinkedInt a1 = new LinkedInt(a);
        LinkedInt a2 = new LinkedInt(b);
        a1 = a1.populate();
        a2 = a2.populate();
        a1.combine();
        a2.combine();

        LinkedInt sum = Trueadd(a1, a2);
        sum.combine2();

    //        LinkedInt sum = a1;
    }

}
`

2 个答案:

答案 0 :(得分:3)

当前的问题是,当事件稍后触发时,navItem的值不同。要解决此常见问题,请使用范围IIFE(立即调用函数表达式):

function loadNav(nav){
    for(item in nav){
        var navItem = nav[item];
        var element = $("<div>" + navItem.text + "</div>");
        (function(navItem){
            element.click(function(){
                getContent(navItem.id,navItem.type);
                //in practice I'm getting two click listeners with a navItem.id of 'litGL' and a navItem.type of 'b'
            });
        })(navItem);
        $('#horzNav').append(element);
    }
}

更好的解决方案包括将require属性放入注入的元素中,然后在事件时提取它们。这简化了事件处理程序并消除了对原始navItem变量的依赖。

e.g。类似的东西:

function loadNav(nav){
    for(var i = 0; i < nav.length; i++){
        var navItem = nav[i];
        var element = $("div", {id: navItem.id}).html(navItem.text).data('type', navitem.type ).appendTo('#horzNav');
    }
}

并使用带有选择器的委托事件处理程序:

$(function () {
    $(document).on("click", ".navItem", function () {
        getContent($(this).attr("id"), $(this).data("type"));
    });
});

这可以通过监听事件(例如点击)来冒泡到一个不变的祖先元素(例如document),然后将选择器应用于泡泡中的项目-chain,然后仅将函数应用于导致事件的匹配元素

这样的结果是项目只需要在活动时间匹配,而不是在活动登记时。非常适合动态添加项目。

如果没有其他祖先更接近/方便,

document是最好的默认值。不要将body用于委派事件,因为它有错误(样式可能导致它无法获取鼠标事件)。

答案 1 :(得分:2)

您的问题是确定范围,但您确实需要委派该事件(否则,如果您有100个元素,那就是100个事件:/),那么您可以指定属性需要在标记内使用数据属性,例如:

$(function () {
    $(document).on("click", ".navItem", function () {
        getContent($(this).attr("id"), $(this).data("type"));
    });
});

然后您的loadNav将是:

function loadNav(nav){
    for(item in nav){
        var navItem = nav[item];
        var element = $(document.createElement("div"));
        element.html(navItem.text);
        element.prop("id", navItem.id);
        element.data("type", navItem.type);
        $('#horzNav').append(element);
    }
}