首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >除了在这里创建一个封闭之外,还有什么可供选择的?

除了在这里创建一个封闭之外,还有什么可供选择的?
EN

Stack Overflow用户
提问于 2015-02-24 16:37:58
回答 2查看 47关注 0票数 0

假设我们有一个简单对象的列表:

代码语言:javascript
复制
var things = [
  { id: 1, name: 'one' },
  { id: 2, name: 'two' },
  { id: 3, name: 'three' }
];

我们需要迭代这些对象,并将它们注册为一些后续事件的参数。朴素的方法在所有回调之间共享相同的对象引用,因此每个回调都针对最后一个项触发:

代码语言:javascript
复制
for (var i = 0; i < things.length; i++) {
  var o = things[i];
  setTimeout(function() { doSomethingWith(o); }, i * 1000);
}

一个典型的解决方案是创建一个闭包,限制对象引用的范围:

代码语言:javascript
复制
for (var i = 0; i < things.length; i++) {
  (function() {
    var o = things[i];
    setTimeout(function() { doSomethingWith(o); }, i * 1000);
  })();
}

如果我们不是针对IE<9,我们可以依靠.forEach()

代码语言:javascript
复制
things.forEach(function(o, i) {
  var o = things[i];
  setTimeout(function() { doSomethingWith(o); }, i * 1000);
});

但是,我们最终还是在将匿名函数传递给forEach()时创建了一种闭包。

是否有一种在没有闭包或函数引用的情况下完成此操作的方法?

根本的问题有三个方面:

  1. 不太重要:--传递到setTimeout()中的函数引用(或任何可能的)--使您(我)感觉您正在创建一个闭包。所以,我倾向于忘记外部封闭。
  2. 更重要的是:附加函数/闭包声明鼓励“箭头代码”。对于复杂操作,当代码移出屏幕时,复杂操作的代码可读性会很快恶化.这可能由.forEach()在IE>9中解决,除非应用程序或组织风格指南为闭包指定换行符+缩进。
  3. importantly: I非常肯定有一个简单的方法来处理这个问题。我觉得很傻,因为我现在没有想到这一点。

也许更好的方法是:,在我们开始强制创建闭包之前,我们都做了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-02-24 16:55:42

我不认为在这里使用闭包有什么问题。它们是javascript中的自然工具,对于具有本地状态的异步回调非常必要--因为我们希望避免全局状态。

如果您非常关心缩进,可以将作用域提供的IEFE与循环放在同一行上:

代码语言:javascript
复制
for (var i = 0; i < things.length; i++) (function() {
  var o = things[i];
  setTimeout(function() { doSomethingWith(o); }, i * 1000);
}());

否则,您已经很好地使用了forEach。注意,您不需要在代码中关心IE<=8,因为如果您想支持forEach,那么它是微不足道的。

当然,ES6将为我们提供一个用新语法解决这个very common problemlet语句--您需要使用一个6到5的转换程序:

代码语言:javascript
复制
for (let i = 0; i < things.length; i++) {
//   ^^^
  var o = things[i];
  setTimeout(function() { doSomethingWith(o); }, i * 1000);
}

如果您想要一个非常清晰的代码组织,请将闭包显式化:

代码语言:javascript
复制
function makeDoer(thing) {
    return function() { doSomethingWith(thing); };
}
for (var i = 0; i < things.length; i++) {
    setTimeout(makeDoer(things[i]), i*1000);
}

在我们开始强制创建闭包之前,我们都做了什么?

我们使用全球状态,并以不同的方式解决我们的问题。例如,您的情况可以通过半递归函数来处理,这样做要好得多:

代码语言:javascript
复制
var i = 0;
function next() {
    if (i < things.length) {
        doSomethingWith(things[i++]);
        setTimeout(next, 1000);
    }
}
next();
票数 1
EN

Stack Overflow用户

发布于 2015-02-24 18:16:57

我想出了两种不同的方法。第一个方法是将参数绑定到该方法的调用。它在函数中克隆参数thingsi并使用它作为参数。

代码语言:javascript
复制
for (var i = 0; i < things.length; i++) {
  var o = things[i];
  setTimeout(doSomethingWith.bind(null, things[i]), i * 1000);
} 

第二种方式,

setTimeout在ms中的参数时间之后,接受您将调用的函数中的参数,它在定义参数时也会复制值,因此变量值可以在之后更改,setTimeout将保证将正确的值作为参数传递。

代码语言:javascript
复制
for (var i = 0; i < things.length; i++) {
 var o = things[i];
 setTimeout(function(param) { doSomethingWith(param); }, i * 1000, o);
}

希望能帮上忙!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28701290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档