在JavaScript中循环x次的典型方法是:

for (var i = 0; i < x; i++)
  doStuff(i);

但我不想使用++运算符或任何可变变量。那么在ES6中,是否有一种方法来循环x乘以另一种方法?我喜欢Ruby的机制:

x.times do |i|
  do_stuff(i)
end

JavaScript/ES6中有类似的吗?我可以欺骗自己的生成器:

function* times(x) {
  for (var i = 0; i < x; i++)
    yield i;
}

for (var i of times(5)) {
  console.log(i);
}

当然,我仍然在使用i++。至少它在视线之外:),但我希望在ES6中有更好的机制。


当前回答

我认为最好的解决方案是使用let:

for (let i=0; i<100; i++) …

这将为每个主体求值创建一个新的(可变的)i变量,并确保i只在循环语法中的增量表达式中更改,而不是从其他任何地方更改。

我可以作弊,自己做一个发电机。至少i++是看不到的:)

在我看来,这应该足够了。即使在纯语言中,所有的操作(或者至少它们的解释器)都是由使用突变的原语构建的。只要它的作用域是正确的,我看不出这有什么错。

你应该可以接受

function* times(n) {
  for (let i = 0; i < n; i++)
    yield i;
}
for (const i of times(5)) {
  console.log(i);
}

但我不想使用++运算符或任何可变变量。

那么你唯一的选择就是使用递归。你也可以在没有可变i的情况下定义生成器函数:

function* range(i, n) {
  if (i >= n) return;
  yield i;
  return yield* range(i+1, n);
}
times = (n) => range(0, n);

但对我来说,这似乎有点过头了,可能会有性能问题(因为尾调用消除无法用于返回收益*)。

其他回答

const times = 4;
new Array(times).fill().map(() => console.log('test'));

这段代码将console.log测试4次。

for (let i of Array(100).keys()) {
    console.log(i)
}

这不是我要教的东西(或者在我的代码中使用),但这里有一个值得codegolf使用的解决方案,无需改变变量,不需要ES6:

Array.apply(null, {length: 10}).forEach(function(_, i){
    doStuff(i);
})

更像是一个有趣的概念证明,而不是一个有用的答案,真的。

发电机吗?递归?为什么这么讨厌突变?: -)

如果它是可以接受的,只要我们“隐藏”它,那么只要接受一元操作符的使用,我们就可以让事情变得简单:

Number.prototype.times = function(f) { let n=0 ; while(this.valueOf() > n) f(n++) }

就像在ruby中:

> (3).times(console.log)
0
1
2

在我看来,这个问题最正确的答案(这是有争议的)隐藏在Sasha Kondrashov的评论中,也是最简洁的,只用了两个字:“不”。没有比Ruby的语法更好的for循环替代函数了。我们可能希望有一个,但就是没有。

问题中没有明确说明,但我认为任何“循环N次”问题的解决方案都不应该分配内存,至少不与N成正比。这个标准将排除大多数“原生javascript”的答案。

其他答案显示了Ruby中的实现,这很好,除了这个问题显式地要求本机javascript解决方案。这个问题已经有了一个非常不错的手卷解决方案,可以说是最易读的解决方案之一。