ES6实现无mutation账单计算 如何规避变量突变问题
ES6无突变规范下的账单分摊函数改造方案
你当前代码中使用let声明的balance变量在迭代过程中被反复重赋值,属于函数内部的状态突变,虽然没有直接修改入参对象,但不符合纯函数无状态变更的要求。要彻底规避突变问题,核心是把迭代过程中需要传递的余额状态,和每次生成的新欠款列表共同作为reduce的累加值传递,全程不使用可重赋值的临时变量。
改造思路
- 将处理应收方的reduce累加器从单一的欠款人数组,扩展为同时存储「当前待分配的应收余额」和「最新欠款人列表」的结构,所有状态随迭代累加器传递,不依赖外部可变变量
- 所有对象、数组的更新全程使用展开运算符做浅拷贝,不修改任何原有引用
- 每轮迭代处理单个欠款人时,基于传入的余额值直接计算划转金额,计算完成后返回更新后的余额和欠款列表作为下一轮迭代的输入,全程无变量重赋值
改造后完整代码
const users = [ { id: 1, username: "John One", amount: 50 }, { id: 2, username: "John Two", amount: 75 }, { id: 3, username: "John Three", amount: 100 }, { id: 4, username: "John Four", amount: 125 }, { id: 5, username: "John five", amount: 150 }, { id: 6, username: "John six", amount: 50 }, { id: 7, username: "John seven", amount: 150 }, { id: 8, username: "John eight", amount: 250 }, { id: 9, username: "John nine", amount: 150 }, { id: 10, username: "John Ten", amount: 100 }, ] const total = users.reduce((acc, user) => acc + user.amount, 0); const perPersonShare = total / users.length; const sortedUsers = users.map((user) => ({ ...user, amount: user.amount - perPersonShare, hasToPay: [] })); const negativeAmount = sortedUsers.filter(user => user.amount < 0); const positiveAmount = sortedUsers.filter(user => user.amount > 0); const res = positiveAmount.reduce((acc, receiver) => { return acc.owers.reduce((innerAcc, ower) => { if (ower.amount === 0 || innerAcc.remainingReceive === 0) { return { ...innerAcc, owers: [...innerAcc.owers, ower] } } const owerOweAmount = Math.abs(ower.amount); if (innerAcc.remainingReceive <= owerOweAmount) { const updatedOwer = { ...ower, hasToPay: [...ower.hasToPay, { to: receiver.username, amount: innerAcc.remainingReceive }], amount: ower.amount + innerAcc.remainingReceive, }; return { remainingReceive: 0, owers: [...innerAcc.owers, updatedOwer] } } const updatedOwer = { ...ower, hasToPay: [...ower.hasToPay, { to: receiver.username, amount: owerOweAmount }], amount: 0, }; return { remainingReceive: innerAcc.remainingReceive - owerOweAmount, owers: [...innerAcc.owers, updatedOwer] } }, { remainingReceive: receiver.amount, owers: [] }); }, { remainingReceive: 0, owers: negativeAmount }).owers; console.log(JSON.stringify(res, 0, 2)) console.log(perPersonShare); console.log(total);
关键改动说明
- 全程没有使用
let声明可重赋值变量,所有状态都通过reduce累加器在迭代链路中传递,彻底消除了内部状态突变 - 所有数组、对象更新都生成新的引用,不会修改原始入参和中间过程生成的数据集
- 计算逻辑和原有代码完全一致,运行结果和原实现无差异
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

