有没有一个机制在ES6(ECMAScript 6)没有可变variables循环x次?

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

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

但是我不想使用++运算符或者任何可变variables。 那么在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++ 。 至less它是看不见的:),但我希望在ES6中有一个更好的机制。

好!

下面的代码是使用ES6语法编写的,但是可以很容易地用ES5编写,甚至更less。 ES6 不是要求创build一个“循环x次的机制”


如果你不需要callback中的迭代器 ,这是最简单的实现

 const times = x => f => { if (x > 0) { f() times (x - 1) (f) } } // use it times (3) (() => console.log('hi')) // or define intermediate functions for reuse let twice = times (2) // twice the power ! twice (() => console.log('double vision')) 

使用ES2015 Spread操作符 :

[...Array(n).keys()]

 const res = [...Array(10)].map((_, i) => { return i * 10; }); // as a one liner const res = [...Array(10)].map((_, i) => i * 10); 

或者如果你不需要结果:

 [...Array(10)].forEach((_, i) => { console.log(i); }); // as a one liner [...Array(10)].forEach((_, i) => console.log(i)); 
 for (let i of Array(100).keys()) { console.log(i) } 

我认为最好的解决办法是使用let

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

这将为每个身体评估创build一个新的(可变的) ivariables,并确保只在循环语法中的增量expression式中更改i ,而不是从其他任何地方更改。

我可以作弊,做我自己的发电机。 至lessi++是看不见的:)

这应该是足够的imo。 即使在纯粹的语言中,所有的操作(或者至less是他们的解释器)都是从使用变异的原语开始构build的。 只要它有合适的范围,我看不出有什么问题。

你应该没事的

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

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

那么你唯一的select是使用recursion。 你也可以定义这个生成器函数,而不需要可变的i

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

但是,这似乎矫枉过正,可能会有性能问题(因为tail call消除不可用于return yield* )。

答案:2015年12月9日

就我个人而言,我发现接受的答案既简洁(好)又简洁(坏)。 欣赏这个声明可能是主观的,所以请阅读这个答案,看看你是否同意

问题中给出的例子就像Ruby的一样:

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

在JS中使用下面的expression将允许:

 times(x)(doStuff(i)); 

这里是代码:

 let times = (n) => { return (f) => { Array(n).fill().map((_, i) => f(i)); }; }; 

而已!

简单的例子用法:

 let cheer = () => console.log('Hip hip hooray!'); times(3)(cheer); //Hip hip hooray! //Hip hip hooray! //Hip hip hooray! 

或者,按照接受的答案的例子:

 let doStuff = (i) => console.log(i, ' hi'), once = times(1), twice = times(2), thrice = times(3); once(doStuff); //0 ' hi' twice(doStuff); //0 ' hi' //1 ' hi' thrice(doStuff); //0 ' hi' //1 ' hi' //2 ' hi' 

附注 – 定义一个范围函数

类似的/相关的问题,使用基本上非常相似的代码结构,可能是(核心)JavaScript中有一个方便的Range函数,类似于下划线的范围函数。

使用n个数字创build一个数组,从x开始

下划线

 _.range(x, x + n) 

ES2015

几个替代品:

 Array(n).fill().map((_, i) => x + i) Array.from(Array(n), (_, i) => x + i) 

演示使用n = 10,x = 1:

 > Array(10).fill().map((_, i) => i + 1) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] > Array.from(Array(10), (_, i) => i + 1) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] 

在我进行的一个快速testing中,上面的每一个都使用我们的解决scheme和doStuff函数运行了一百万次,前一种方法(Array(n).fill())稍微快一点。

不是我会教的东西(或者在我的代码中使用过),但是这里有一个代码高效的解决scheme,不需要variablesvariables,也不需要ES6:

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

更有意义的certificate概念的东西,而不是一个有用的答案,真的。

 Array(100).fill().map((_,i)=> console.log(i) ); 

该版本符合OP对不变性的要求。 另外考虑使用reduce而不是map取决于你的用例。

如果您不介意原型中的一点突变,这也是一种select。

 Number.prototype.times = function(f) { return Array(this.valueOf()).fill().map((_,i)=>f(i)); }; 

现在我们可以做到这一点

 ((3).times(i=>console.log(i))); 

+1给arcseldon。 .fillbuild议。

我觉得这很简单:

 [...Array(3).keys()] 

要么

 Array(3).fill() 

Afaik,在ES6中没有类似于Ruby的times方法的机制。 但是你可以通过使用recursion来避免突变:

 let times = (i, cb, l = i) => { if (i === 0) return; cb(l - i); times(i - 1, cb, l); } times(5, i => doStuff(i)); 

演示: http : //jsbin.com/koyecovano/1/edit?js,console

如果你愿意使用一个库,还有lodash _.times或下划线_.times

 _.times(x, i => { return doStuff(i) }) 

注意这会返回一个结果数组,所以它更像这个ruby:

 x.times.map { |i| doStuff(i) } 

发电机? recursion? 为什么这么多hatin'对mutatin'? 😉

如果只要我们“隐藏”它就可以接受,那么只要接受一个一元运算符的使用,我们就可以保持简单

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

就像在ruby:

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

在function范式中, repeat通常是一个无限recursion函数。 要使用它,我们需要懒惰评估或延续传球风格。

懒惰评估函数重复

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

处理function方面:

 function times(n, f) { var _f = function (f) { var i; for (i = 0; i < n; i++) { f(i); } }; return typeof f === 'function' && _f(f) || _f; } times(6)(function (v) { console.log('in parts: ' + v); }); times(6, function (v) { console.log('complete: ' + v); });