javascript - 为什么这个递归函数会覆盖第二次调用的值?
问题描述
对不起标题,我什至不知道如何表达这里发生的事情。
我正在开发一个支持多种货币的 React 费用跟踪程序。被跟踪的费用可以任意嵌套在 JSON 对象中。
entertainment: {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
}
}
费用可以直接在其中存储金额,但它也可以作为“父”类别来进一步详细说明子费用。
为了显示费用的总价值,我编写了一对函数:
sumValues(values)
对对象数组求和_values
(值对象是货币代码和整数的键值存储)
totalExpense(expense)
返回费用的总值。即_values
它拥有的任何东西,+ 任何儿童费用的总费用。
我以为我把这些写成纯函数,但是当totalExpense()
递归调用费用的第一个孩子时,返回错误的总数。
totalExpense(entertainment);
//-> Object { USD: 137, AUD: 116 }
好的
totalExpense(entertainment['food & drink']);
//-> Object { AUD: 111, USD: 2 }
好的
totalExpense(entertainment);
totalExpense(entertainment['food & drink']);
//-> Object { AUD: 139, USD: 4 }
不好
我已经在这段代码上戳了几个小时了,但是我这辈子看不到发生了什么:
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
}
return acc;
});
};
totalExpense = expense => {
const values = [];
if (expense['_values']) {
values.push(expense['_values']);
}
const subExpenses = Object.keys(expense).filter(child => {
return child[0] !== '_';
});
if (subExpenses.length > 0) {
for (const subExpense of subExpenses) {
let subtotal = this.totalExpense(expense[subExpense]);
values.push(subtotal);
}
}
if (values.length) {
return this.sumValues(values);
} else {
throw Error('No values in this expense');
}
};
render() {
const entertainment = {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
},
};
console.log(this.totalExpense(entertainment));
console.log(this.totalExpense(entertainment['food & drink']));
console.log(this.totalExpense(entertainment['minigolf']));
return;
}
解决方案
问题是您的reduce
回调的初始值是values
数组中的第一项,然后您继续分配给该项目:
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
因此,每次sumValues
调用第一项都会发生变异。相反,提供一个空对象作为 的初始值reduce
:
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
}
return acc;
}, {});
};
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency] ?
(acc[currency] = acc[currency] + cur[currency]) :
(acc[currency] = cur[currency]);
}
return acc;
}, {});
};
totalExpense = expense => {
const values = [];
if (expense['_values']) {
values.push(expense['_values']);
}
const subExpenses = Object.keys(expense).filter(child => {
return child[0] !== '_';
});
if (subExpenses.length > 0) {
for (const subExpense of subExpenses) {
let subtotal = this.totalExpense(expense[subExpense]);
values.push(subtotal);
}
}
if (values.length) {
return this.sumValues(values);
} else {
throw Error('No values in this expense');
}
};
const entertainment = {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
},
};
console.log(totalExpense(entertainment));
console.log(totalExpense(entertainment['food & drink']));
推荐阅读
- python - 使用 dcc.Store 在另一个页面中绘制 Dash 共享回调输入
- nunit - Nunit 测试适配器未发现测试
- c# - 如何获取 XML 节点的内容(或将 PowerShell 函数转换为 C#)
- kubernetes - 如何访问容器中的 minikube IP 和服务端口?
- excel - VBA 错误:对象“_Global”的“范围”失败
- r - 如何使用两个分类变量从数据框中采样行?
- laravel - Laravel 类别树 - 顺序子级
- git - 如何在 Git 挂钩脚本中检测 GUI 应用程序是否正在启动提交?
- azure - azure 函数是否适合长时间运行的任务?
- python - 意外的结果树遍历 - Python