Using 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);
}
Using .forEach
addSales(sales: Sale[]) {
sales.forEach(sale => {
this.total += sale.total;
this.tax += sale.tax;
this.discount += sale.discount;
this.qty += sale.qty;
});
}
Using .forEach
here seems to be more readable, and perhaps better in performance since it will only loop through it once.
But in the long run, does it make it less modular? I have some parts of my code in which started with small .forEach
block, but overtime it grew in size and was somehow difficult to refactor, since they were "tied" to each other.
Could you share your experience on this?
Richard's answer is good but if you want to stick with reduce
to avoid the albeit localized mutation you can do so while still visiting each object only once. In fact the beauty of reduce
is that we can transform an array into any arbitrary value that we want, so let's have fun with it
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});
With respect to the specific the question about modularity, using the above style is by no means more modular, but it does encourage us to write more testable code as we express things in terms of inputs and outputs to functions. The function above can be tested very easily, while the imperative version that mutates the class instance's dynamic binding is more complicated to test although not necessarily by much in this case.
Interestingly, it's not really about using reduce
versus forEach
at all. In fact the above function could be written with forEach
and it would be as maintainable and testable and as modular as it is with reduce
. It has more to do with how using reduce
gets us in the mind frame of expressing our interfaces in terms of values instead of modifying state that is associated with many producers and consumers to implicitly move the program forward.
There's nothing wrong with using forEach
here, and it's certainly more efficient than doing multiple calls to reduce
(albeit to a negligible degree unless sales
can contain a very large number if values). It's also more readable, as you mentioned
You could pass this
to reduce
as the seed and do all the changes together, but since the code is mutating the instance there's not much to be gained by using a more functional approach.
I'd stick with forEach.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.