在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中有更好的机制。


当前回答

我来晚了,但由于这个问题经常出现在搜索结果中,我只想添加一个解决方案,我认为它在可读性方面是最好的,同时不长(这对于任何代码库都是理想的)。它会变异,但我愿意为KISS原则做出妥协。

let times = 5
while( times-- )
    console.log(times)
// logs 4, 3, 2, 1, 0

其他回答

此解决方案的优点

最容易阅读/使用(我觉得) 返回值可以用作和,也可以忽略 普通es6版本,也链接到TypeScript版本的代码

缺点 ——突变。只是内在我不在乎,也许其他人也不在乎。

示例和代码

times(5, 3)                       // 15    (3+3+3+3+3)

times(5, (i) => Math.pow(2,i) )   // 31    (1+2+4+8+16)

times(5, '<br/>')                 // <br/><br/><br/><br/><br/>

times(3, (i, count) => {          // name[0], name[1], name[2]
    let n = 'name[' + i + ']'
    if (i < count-1)
        n += ', '
    return n
})

function times(count, callbackOrScalar) {
    let type = typeof callbackOrScalar
    let sum
    if (type === 'number') sum = 0
    else if (type === 'string') sum = ''

    for (let j = 0; j < count; j++) {
        if (type === 'function') {
            const callback = callbackOrScalar
            const result = callback(j, count)
            if (typeof result === 'number' || typeof result === 'string')
                sum = sum === undefined ? result : sum + result
        }
        else if (type === 'number' || type === 'string') {
            const scalar = callbackOrScalar
            sum = sum === undefined ? scalar : sum + scalar
        }
    }
    return sum
}

TypeScipt版本 https://codepen.io/whitneyland/pen/aVjaaE?editors=0011

在函数式范式中,重复通常是一个无限递归函数。要使用它,我们需要惰性求值或延续传递样式。

惰性求值函数重复

const重复= f = > x = > [x,() = >重复(f) (f (x))); Const take = n => ([x, f]) => n === 0 ?X:取(n - 1) (f()); console.log ( 取(8)(repeat(x => x * 2) (1)) // 256 );

我使用一个thunk(一个没有参数的函数)来实现Javascript中的惰性求值。

延续传递样式的函数重复

const重复= f = > x = > [x, k = > k(重复(f) (f (x)))); Const take = n => ([x, k]) => n == 0 ?X: k(取(n - 1)); console.log ( 取(8)(repeat(x => x * 2) (1)) // 256 );

CPS一开始有点吓人。然而,它总是遵循相同的模式:最后一个参数是continuation(一个函数),它调用自己的主体:k => k(…)。请注意CPS将应用程序翻过来,即take(8)(重复…)变成k(take(8))(…)其中k是部分应用的重复。

结论

通过将重复(repeat)与终止条件(take)分离,我们获得了灵活性——将关注点分离到痛苦的尽头:D

我认为最好的解决方案是使用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);

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

我把它放在这里。如果你正在寻找一个不使用数组的紧凑函数,并且你对可变性/不可变性没有问题:

var g =x=>{/*your code goes here*/x-1>0?g(x-1):null};
 

我做了这个:

function repeat(func, times) {
    for (var i=0; i<times; i++) {
        func(i);
    }
}

用法:

repeat(function(i) {
    console.log("Hello, World! - "+i);
}, 5)

/*
Returns:
Hello, World! - 0
Hello, World! - 1
Hello, World! - 2
Hello, World! - 3
Hello, World! - 4
*/

变量i返回它循环的次数-如果你需要预加载x数量的图像,这很有用。