An array is an ordered collection of references or primitive values. An object groups properties by name. These structures are easy to share accidentally: assigning an array to a second variable does not duplicate its storage. Before changing a collection, identify who owns it and what the caller expects after your function returns.
const original = [{amount: 2}, {amount: 1}];
const copied = [...original];
copied.reverse();
console.log(original[0].amount, copied[0].amount);
copied[0].amount = 7;
console.log(original[1].amount);Spread creates a fresh outer array, so reversing the copy does not reorder the original. The nested records remain shared, so changing a record through either array is visible through the other. A shallow copy is enough when you only rearrange references; it is insufficient when you mutate the referenced records. The build avoids changing those records and creates fresh summary objects instead.
Choose array methods by their effects. map produces a new array of transformed results. filter produces a new array containing selected original values. sort, reverse, push and splice mutate their receiver. A callback can itself mutate external objects even when the array method returns a fresh array, so the method name alone does not prove that a complete operation is pure.
Grouping needs a mapping from customer to accumulated state. A Map treats every customer string as data; special object property names do not become prototype operations. Updating an existing key preserves one aggregate for that customer. The aggregate must account for every occurrence, including zero amounts and negative adjustments.
const totals = new Map();
for (const amount of [3, -1, 0]) {
totals.set("sam", (totals.get("sam") ?? 0) + amount);
}
console.log(totals.get("sam"));Encounter order and required output order are different concerns. A Map remembers insertion order; it does not sort keys. The report contract explicitly uses JavaScript string comparisons. Avoid locale-dependent ordering when a deterministic machine-readable format is required. Numeric sorting needs a comparator too: default array sorting compares string representations, so [2,10].sort() does not express numeric ascending order.
For the build, first copy and sort the outer array, then accumulate new records in a Map. Another valid implementation aggregates first and sorts the result. Either approach must preserve input order and nested record contents. Test repeated customers, negative adjustments, empty input and customer names such as __proto__. Finally mutate a returned summary and call the function again: a prior caller must not be able to change a future report through shared result state. These checks turn a vague claim about avoiding mutation into a concrete ownership contract.