优雅地在CoffeeScript中执行一些对象属性

时间:2012-12-19 10:54:30

标签: coffeescript

我有一系列的项目如下:

@items = [
  {price: 12, quantity:1}, 
  {price: 4, quantity:1}, 
  {price: 8, quantity:1}
]

我正在寻找这样的事情:

sumPrice: ->
  @items.sum (item) -> item.price * item.quantity

或者尽可能接近这一点,这使得每个阅读代码的人都能轻松理解发生的事情。

到目前为止,我提出了:

sumPrice: ->
   (items.map (a) -> a.price * a.quantity).reduce (a, b) -> a + b
  • 包含太多功能性魔法
  • 失去描述性

sumPrice: ->
   sum = 0
   for item in items
     sum += item.price * item.quantity
   sum
  • 新手JS /咖啡程序员可以理解
  • 感觉有点愚蠢

我喜欢CoffeeScript,所以我希望有更好的解决方案。我想念的类似场景。

4 个答案:

答案 0 :(得分:13)

功能风格并不是那么糟糕。 CoffeeScript允许你像这样美化你的代码:

items
  .map (item) ->
    item.price * item.quantity
  .reduce (x,y) ->
    x+y

此代码比单行代码更容易理解。

如果您不喜欢map,可以改用for。像这样:

(for item in items
  item.price * item.quantity)
  .reduce (x,y)->x+y

或者像这样:

prods = for item in items
  item.price * item.quantity
prods.reduce (x,y)->x+y

或者您可以为数组添加自己的sum()方法:

Array::sum = -> @reduce (x,y)->x+y
(item.price * item.quantity for item in items).sum()

答案 1 :(得分:11)

如果您想将解决方案表达为@items.sum (item) -> item.price * item.quantity,可以向sum添加Array方法:

Array::sum = (fn = (x) -> x) ->
  @reduce ((a, b) -> a + fn b), 0

sum = @items.sum (item) -> item.price * item.quantity

请注意,我将0作为reduce的初始值传递,因此会为每个数组值调用fn回调。


如果你不喜欢扩展内置对象,我想如果你在自己的函数中提取计算单个数组项的总价格的逻辑,你可以优雅地将总和表示为单个减少:

itemPrice = (item) -> item.price * item.quantity

sum = items.reduce ((total, item) -> total + itemPrice item), 0

答案 2 :(得分:7)

您可以使用解构来略微简化代码:

sumPrice: ->
    sum = 0
    sum += price * quantity for {price, quantity} in @items
    sum

我认为没有办法摆脱sum的显式初始化。虽然Coffeescript的for循环语法有助于简化原本会使用map()的代码,但它实际上没有任何类似的简化reduce()类型的操作,这就是{{1}在这里做。

正如评论中所提到的,此解决方案优于调用sumPricereduce()的一个优点是它避免了创建和重复调用函数的开销。

答案 3 :(得分:2)

sum = 0
value = (item) ->
  item.price * item.quantity
sum += value(item) for item in @items