数组的惯用语种群只要属性值即可

时间:2017-03-17 20:52:49

标签: javascript arrays oop idiomatic

我有一个骰子滚动机器人,通过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(...是一个丑陋的黑客,将this作为state传递似乎是一个标志,我做错了。

我应该使用Array方法吗?或者for循环仍然是最简洁的方法吗?

2 个答案:

答案 0 :(得分:2)

重复一次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)));
}

答案 1 :(得分:1)

我想我已经弄明白这应该怎么做了。

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

  

箭头函数不会创建自己的this上下文,因此this在封闭的上下文中具有其原始含义。

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

第二个问题:不是滥用reduce()的初始值参数和this伪造context对象,而是使用闭包:

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

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

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

对于第三个问题,将数组填充为对象属性的大小,以便多次调用一个函数...

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