【问题标题】:Difference between two ways of using a closure使用闭包的两种方式之间的区别
【发布时间】:2014-04-11 10:16:37
【问题描述】:

以下示例在 for 循环中使用了闭包机制

我知道闭包的目的,但我不知道以下代码之间的最佳选择是什么,尤其是为什么一个会比另一个更好?

// First case: Closure wraps the ajax call
$('#container').on('click', 'a.log', function (e) {
  _t = this;
  for (var i = 0; i < 5; i++) {
    (function (j) {
      $.ajax({
        url: "/logger",
        context: _t
      }).done(function () {
        $(this).addClass("done" + j);
      });
    })(i);
  };
});

// -------------------------------------------------------

// Second case :closure wraps the ajax callback function
$('#container').on('click', 'a.log', function (e) {
  for (var i = 0; i < 5; i++) {
    $.ajax({
      url: "/logger",
      context: this
    }).done(
      (function (j) {
        return function () {
          $(this).addClass("done" + j);
        };
      })(i)
    );
  };
});

我希望有人能准确地解释我。

感谢您的关注和花费的时间。

【问题讨论】:

  • 没什么区别,但我个人会使用第一种情况,因为它更明显地表明我正在“锚定”循环值。

标签: javascript jquery closures


【解决方案1】:

方法#1 侧重于IEFE 用于保存循环迭代变量这一事实。你甚至可以将它写在一行上——整个循环体进入函数:

for (var i=0; i<5; i++) (function(j) {
    …
})(i);

方法 #2 更侧重于 IEFE 用于在回调闭包范围内提供 j 的事实 - 您可以将其称为 (function makeCallback(j){ … })(i);

一般来说,使用对您来说更易读的内容。您可能总是希望使用 #1,因为它可以更轻松地创建其他闭包。


在这种特定情况下,#1 导致了一个错误:您作为 context 参数传递给 ajax 函数的 this value 不是您期望的事件处理程序,而是 IEFE - undefined(或 window 在草率模式下)。你要么选择#2,要么明确地传递它:

for (var i=0; i<5; i++) (function(j) {
    …context:this…
}).call(this, i);
// or
for (var i=0; i<5; i++) (function(el, j) {
    …context:el…
})(this, i);

【讨论】:

  • 感谢您注意到我this 的问题,我会更正它;) ...顺便编辑
  • 抱歉,IEFE 代表什么?
  • 立即执行的函数表达式。您还会在 IIFE 中听到 Invoked。
【解决方案2】:

您还可以考虑将立即调用的函数表达式移到单独的函数中:

$('#container').on('click', 'a.log', function (e) {
  for (var i = 0; i < 5; i++) {
      doLogging(i, this);
  };
});

function doLogging(i, clickedElement) {
   $.ajax({
      url: "/logger",
      context: clickedElement
   }).done(function () {
      $(clickedElement).addClass("done" + i);
   });
}

我认为理解发生了什么要容易得多,而且您不必引入新的变量名称“j”。

你没有发送被点击的元素,你可以使用apply()调用doLogging:

doLogging.apply(this, [i]);

在这种情况下,doLogging() 内的this 将引用被点击的元素。

【讨论】:

  • 谢谢,分离函数方式我已经知道了。我只是想对这两个闭包用例进行一些解释。
  • 变量重命名为 j 有点令人困惑,是的,但在原始解决方案中也不是必需的。你可以很容易地写(function(i){ … })(i);
猜你喜欢
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-18
  • 2015-04-22
  • 1970-01-01
相关资源
最近更新 更多