数组的惯用填充只要 属性 的值

Idiomatic population of an array as long as a property's value

我有一个掷骰子的机器人,可以通过 var roll = new Roll('4#2d20+3') 吐出结果。该构造函数使对象的属性从字符串参数中解析出来,类似于:

aRoll = {
  text: '4#2d20+3',
  times: 4,
  dice: 2,
  sides: 20,
  modifier: 3,
  roll: function() {...}
}

roll() 方法应该使用对象的属性来生成结果数组。这是一个学习 JavaScript 新功能的练习,所以我很好奇如何最好地完成它。

旧的程序方式:

this.roll = function() {
  var total = 0;

  for (var i=0; i < this.dice; i++) {
    total += Math.floor(Math.random() * this.sides) + 1;
  }

  return total;
}

我对新 Array 功能迭代的尝试:

this.roll = () => Array(this.dice).fill(0).reduce(state => {
  result + Math.floor(Math.random() * state.sides) + 1;
}, this);

这有点有效,但是 Array(x).fill(0).reduce(... 是一个丑陋的 hack,并且将 this 作为 state 传递似乎是我做错事的标志。

我应该使用 Array 方法吗?或者 for 循环仍然是完成此任务的最干净的方法吗?

重复一个函数 n 次的一种方法是

Array.from(Array(n), fn)

为了使所有这些更具可读性,您可以定义,例如

let times = (n, fn) => Array.from(Array(n), fn);
let rand = n => Math.floor(Math.random() * n) + 1;
let sum = a => a.reduce((x, y) => x + y);

然后

roll = function() {
    return sum(
        times(this.dice,
            rand.bind(0, this.sides)));
}

我想我想出了这个“应该”怎么做。

第一期很简单:do not use arrow functions as methods:

An arrow function does not create its own this context, so this has its original meaning from the enclosing context.

this 是面向对象的重点,所以打破它是个坏主意。将 this 作为 map() 的第二个参数传递确实是一种代码味道。

第二个问题:与其滥用 reduce() 的初始值参数 this 来伪造 context 对象,不如使用关闭:

function roll(sides) {
  return (total) => {
    total + Math.floor(Math.random() * sides) + 1;
  };
}

someArray.map(roll(this.sides));

当您将回调作为参数传递,但需要动态地为它们提供调用者未提供的数据时,闭包是经典的解决方案。

至于第三期,填充一个对象大小的数组属性,为了多次调用一个函数...

没有内置的样板方式。 :•) @georg 好心地提供了一个干净的 让我想起了 Ruby 的 Number.times(),如果你有兴趣的话。