【问题标题】:A deep understanding of javascript closures [duplicate]深入理解 javascript 闭包 [重复]
【发布时间】:2013-12-23 19:49:29
【问题描述】:

我正在尝试掌握这段代码,我知道这是一个闭包,但我没有得到我认为应该得到的结果。

这段代码返回了一个 [object MouseEvent],我不明白为什么?

我正在使用此代码向 .addEventListener 添加一个函数调用 (updateProduct),它返回一个 [object MouseEvent]

function addEventListenerToMinPlus(){
    var x, y
    for(var i = 0; i < productItemAll.length; i++){
        x = productItemAll[i].querySelector(".boxNumbers-min")
        x.addEventListener("click", function(i){return function(i){updateProduct(i)}}(i))
        console.log(x)
    }
}

function updateProduct(jow){
    alert(jow)
}

jsFiddle

【问题讨论】:

  • 看在所有神圣事物的份上,把那些分号放回原处。分号省略是魔鬼。
  • 是的,我打算将它们带回生产环境。

标签: javascript function closures addeventlistener


【解决方案1】:

浏览器以事件对象作为第一个参数调用事件处理程序。您的函数被声明为采用单个参数(“i”),因此当您显示它时,就是这样。

我怀疑您的意思是让事件处理程序中的“i”引用外部函数(循环索引)中的“i”。这也行不通,因为循环创建的各种处理程序都将引用同一个共享变量“i”。见this old SO question

【讨论】:

  • 嗨,谢谢你的回答......这个小提琴显示了我想要实现的目标(点击红色 - )。 jsfiddle.net/v4xz5
  • @kevinius 对 - 你明白我的回答吗?您的代码有两个问题:您已经使用“i”作为形式参数创建了事件处理函数,因此函数中的“i”将引用触发事件时传递给函数的任何内容。第二个问题是由于 JavaScript 变量作用域的性质,您会遇到问题。阅读该链接的其他问题的答案。
【解决方案2】:

线

x.addEventListener("click", function(i) { return function(i) { updateProduct(i); }(i) }

产生内部函数的闭包

function(i) { updateProduct(i); }

外部i 在这个内部函数的范围内,但它被它的参数所遮蔽。因此,实际上,内部i 表示传递给单击处理程序(MouseEvent)的第一个参数。如果您希望它保留索引的值,则必须更改其名称。像这样的:

x.addEventListener("click",
    function(i) { return function(e) { updateProduct(i); }(i)
}

现在,在内部函数中,e 是 MouseEvent,i 是外部索引。我已经更新了 JSFiddle:http://jsfiddle.net/Cdedm/2/。按预期单击第一项的减号警报0 和第二项的1

【讨论】:

  • 如何让这件事变得不那么复杂,有没有更简单的方法来完成同样的事情?
  • 如果您试图从其点击处理程序中获得项目的索引,您必须产生某种闭包。另一个选项是从单击处理程序中查找索引,因为处理程序知道刚刚单击的元素(在e.target 中可用)。您知道updateProduct 函数中元素的索引吗?
  • 是的,我必须更新另一个具有相同输出但在另一个位置的 html 表。
  • 在这种情况下,这不是一个糟糕的解决方案。您还可以使用 HTML5 data- 属性来引用另一个表中的相应元素,然后从点击处理程序目标中提取它们以查找您需要更新的元素。但是,这很可能最终会变得更慢(并且可能更混乱)。
  • 我们不能简单地说x.addEventListener("click", function(e) { updateProduct(i); });吗?我假设i 来自外循环。
【解决方案3】:

那是因为您将元素作为参数发送。

你应该尝试这样做:

function addEventListenerToMinPlus(){

    var x, y

    for(var i = 0; i < productItemAll.length; i++){

        x = productItemAll[i].querySelector(".boxNumbers-min")
        x.addEventListener("click", function(){return updateProduct(i)})

        console.log(x)


    }

}

希望这行得通,

问候,

马塞洛

【讨论】:

  • 这也行不通。阅读this question
  • 是的,你是对的。我忘记了当点击被触发时,由于关闭,“i”将成为数组的长度。我认为我的示例应该通过在被调用的函数中设置一个新变量并将其传递给 updateProduct 来工作。例如 x.addEventListener("click", function(){var x = i; return updateProduct(x)});
【解决方案4】:

我认为您正在尝试做这样的事情。您的i 将在单击发生时更改,因此需要将其设置为另一个局部变量,在这种情况下通过新函数上的参数。单击事件处理程序将传递您当前正在获取的事件对象

 function addEventListenerToMinPlus() {
        var x, y;
        for(var i = 0; i < productItemAll.length; i++) {
            x = productItemAll[i].querySelector(".boxNumbers-min");
            x.addEventListener("click", function(i){return function(){updateProduct(i)}}(i));
        }
    }

    function updateProduct(jow) {
        alert(jow);
    }

【讨论】:

  • 如何让这件事变得不那么复杂,有没有更简单的方法来完成同样的事情?
  • 只需删除 i x.addEventListener("click", function(i){return function(){updateProduct(i)}}(i));我会更新答案。
  • 嗨,对不起,这个问题实际上是针对@igorraush...:p
【解决方案5】:

除非你真的真的很清楚自己在做什么,否则你可以整天玩闭包,但仍然无法正确处理这类事情。

到目前为止,一个更易于理解的方法是使用 jQuery 的 .data() 方法将数据(在本例中为 i)与相关元素相关联,以便在点击事件触发,例如:

function addEventListenerToMinPlus() {
    var x, y;
    for(var i = 0; i < productItemAll.length; i++) {
        x = productItemAll[i].querySelector(".boxNumbers-min");
        x.data('myIndex', i);//associate `i` with the element
        x.addEventListener("click", function(i) {
            var i = $(this).data('myIndex');//read `i` back from the element
            updateProduct(i);
        });
        console.log(x);
    }
}

作为记录,工作结束如下:

function addEventListenerToMinPlus() {
    var x;
    for(var i = 0; i < productItemAll.length; i++) {
        x = productItemAll[i].querySelector(".boxNumbers-min");
        x.addEventListener("click", function(i) {//<<<< this is the i you want
            return function() {//<<<< NOTE: no formal variable i here. Include one and you're stuffed!
                updateProduct(i);
            }
        }(i));
        console.log(x);
    }
}

【讨论】:

    猜你喜欢
    • 2013-03-25
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    相关资源
    最近更新 更多