几个小的减少vs一个大的forEach?

时间:2017-10-22 11:53:19

标签: javascript arrays typescript flowtype

使用reduce

addSales(sales: Sale[]) {
  this.total += sales.reduce((ac, sale) => ac + sale.total, 0);
  this.tax += sales.reduce((ac, sale) => ac + sale.tax, 0);
  this.discount += sales.reduce((ac, sale) => ac + sale.discount, 0);
  this.qty += sales.reduce((ac, sale) => ac + sale.qty, 0);
}

使用.forEach

addSales(sales: Sale[]) {
  sales.forEach(sale => {
    this.total += sale.total;
    this.tax += sale.tax;
    this.discount += sale.discount;
    this.qty += sale.qty;
  });
}

在这里使用.forEach似乎更具可读性,可能性能更好,因为它只会循环一次。

但从长远来看,它是否会减少模块化?我的代码的某些部分以小.forEach块开头,但加时它的大小增加,并且在某种程度上难以重构,因为它们彼此“绑定”。

你能分享一下你的经历吗?

2 个答案:

答案 0 :(得分:3)

理查德的答案很好,但是如果你想坚持reduce以避免虽然局部突变,你可以这样做,同时仍然只访问每个对象一次。事实上reduce的美妙之处在于我们可以将数组转换为我们想要的任意值,所以让我们玩得开心

export function tallySales(sales: Sale[]) {
  return sales.reduce((ac, {total, tax, discount, qty}) => ({
    total: ac.total + total,
    tax: ac.tax + tax, 
    discount: ac.discount + discount,      
    qty: ac.qty + qty
  }), {total: 0, tax: 0, discount: 0, qty: 0});

关于模块化的具体问题,使用上述样式绝不是更模块化的,但它确实鼓励我们编写更多可测试的代码,因为我们根据函数的输入和输出来表达事物。上面的函数可以很容易地测试,而改变类实例的动态绑定的命令式版本更难以测试,但在这种情况下不一定很多。

有趣的是,它根本不是关于使用reduceforEach的关系。事实上,上面的函数可以用forEach编写,它可以像reduce一样可维护,可测试和模块化。它更多地与如何使用reduce使我们在思维框架中以值表达我们的接口而不是修改与许多生产者和消费者相关联的状态来隐式地移动程序。

答案 1 :(得分:2)

在这里使用forEach没有任何问题,它肯定比对reduce进行多次调用更有效(尽管可以忽略不计,除非sales可以包含非常大的数字)。它也更具可读性,正如你提到的那样

可以this作为种子传递给reduce并一起完成所有更改,但由于代码正在改变实例,因此使用的内容并不多更实用的方法。

我坚持使用forEach。