【问题标题】:Javascript closure freezing values of incrementer增量器的Javascript闭包冻结值
【发布时间】:2013-07-22 22:26:28
【问题描述】:

我很难理解和使用闭包(是的,我已阅读 How do JavaScript closures work?

我的问题如下:

for (row = 0; row < 10; row++) {
    for (column = 0; column < 10; column++) {

        var target = $("#" + Data.Row[row].Column[column].ID);

        target.mouseenter(function () {
            var position = CalculatePosition($(this));

            alert("row:" + row + ",column:" + column);

            ...
        });
    }
}

正如您所料,只要目标鼠标悬停在行和列上,行和列始终为 9。那么我的问题是,如何冻结行和列的值,以便 mouseevent 匿名函数可以获得它们的预期值?我尝试做类似的事情

target.mouseenter(function() {}.bind(column));

这似乎只适用于列,但当然this 不再指代目标。

【问题讨论】:

  • 不,bind 做了一些你不能在这里使用的不同的事情(另请阅读about the this keyword
  • @Bergi 他可以使用bind 喜欢:function(row, column){}.bind(target, row, column)
  • 我怀疑你想让函数知道点击了哪个元素,每个元素都有不同的 ID。是吗?
  • @Paulpro:啊,没有看到他已经知道处理程序之外的this/target[0]。至少不适用于更大的收藏......

标签: javascript jquery closures


【解决方案1】:

这里最简单的选择通常是定义一个返回处理程序的函数:

function getHandler(row, column)
    return function () {
        var position = CalculatePosition($(this));
        alert("row:" + row + ",column:" + column);
        // ...
    };
}

然后在你的循环中调用这个函数,让你的处理程序在调用时将相关变量“固定”到它们的值:

for (row = 0; row < 10; row++) {
    for (column = 0; column < 10; column++) {
        var target = $("#" + Data.Row[row].Column[column].ID);
        target.mouseenter(getHandler(row, column));
    }
}

您也可以在循环中,在立即执行的匿名函数中执行此操作:

for (row = 0; row < 10; row++) {
    for (column = 0; column < 10; column++) {
        var target = $("#" + Data.Row[row].Column[column].ID);
        target.mouseenter((function(row, column) {
            return function () {
                var position = CalculatePosition($(this));

                alert("row:" + row + ",column:" + column);

                ...
            };
        })(row, column)));
    }
}

但 IMO 更丑陋且难以阅读。

无论哪种情况,这里的基本方法是建立一个新的函数作用域,使用循环变量作为参数;现在,当您在处理程序回调中使用它们时,它们不再是对外部范围变量的引用。

【讨论】:

  • +1 这通过为循环中的每次迭代创建一个新的闭包来工作,并且该闭包也包含鼠标进入处理程序。这样每个元素的处理程序都有自己存储的 x 和 y 值。
  • 谢谢!这个解决方案现在在我的脑海中变得更有意义了。
【解决方案2】:

你可以像这样使用bind(第一个参数是上下文(thisarg)):

target.mouseenter(function(row, column){
    ...
}.bind(target[0], row, column));

但是bind不是跨浏览器,而且你已经在使用jQuery了,所以你应该改用proxy

target.mouseenter($.proxy(function(row, column){
    ...
}, target[0], row, column));

【讨论】:

  • 但您应该使用target[0] 仅获取DOM 元素,或者从处理程序内的this 中删除$()
  • @Bergi 谢谢,我没有注意到target 是一个jQuery 对象(我认为它是来自某个事件处理程序的e.target)。我已将其更新为使用 target[0]
猜你喜欢
  • 2015-01-07
  • 2012-08-28
  • 2021-09-13
  • 2020-01-22
  • 2014-05-09
  • 2019-05-04
  • 2020-05-31
  • 2014-05-27
  • 2016-12-10
相关资源
最近更新 更多