JS循环合并API数据时对象属性被覆盖致赔率缺失问题排查
问题描述
我编写了一段代码用于合并两个API的返回结果,仅保留业务所需的字段数据。我清楚当前实现方式并非最优,大家可能会疑惑为何我不直接使用赔率API,原因是赛事API包含历史数据,而赔率API不提供历史赛事的赔率数据。
目前遇到的异常现象:所有控制台输出日志都能正常打印主、客队的赔率赋值过程,但最终matchesAndOdds对象中仅保留了客队赔率,缺失主队赔率数据。
我猜测是不是odds对象的属性在循环执行过程中被意外覆盖了?
注:实际业务场景中
matches和odds数组包含更多对象元素,此处为避免代码片段过长做了裁剪。
原实现代码:
const odds = [ { "id": "dd7aff0584aee475b4d67ab83655f379", "sport_key": "aussierules_afl", "sport_title": "AFL", "commence_time": "2022-06-30T09:20:00Z", "home_team": "Brisbane Lions", "away_team": "Western Bulldogs", "bookmakers": [ { "key": "unibet", "title": "Unibet", "last_update": "2022-06-29T12:14:33Z", "markets": [ { "key": "h2h", "outcomes": [ { "name": "Brisbane Lions", "price": 1.36 }, { "name": "Western Bulldogs", "price": 3.15 } ] } ] } ] } ] const matches = [ { gametime: "2022-06-30T09:20:00.000Z", home_team: 'Brisbane Lions', away_team: 'Western Bulldogs', ground: 'Gabba', home_points: 108, away_points: 67, selected: null } ] // 两个API的队伍名称映射字典 // ff = 赛事API oa = 赔率API const ffToOa = { "Western Bulldogs": "Western Bulldogs", "Brisbane Lions": "Brisbane Lions", "St Kilda": "St Kilda Saints", "Carlton": "Carlton Blues", "Sydney": "Sydney Swans", "Essendon": "Essendon Bombers", // 兼容墨尔本队更名Naarm的情况 "Melbourne": "Melbourne Demons", "Naarm": "Melbourne Demons", "Adelaide": "Adelaide Crows", "North Melbourne": "North Melbourne Kangaroos", "Geelong": "Geelong Cats", "Collingwood": "Collingwood Magpies", "Gold Coast": "Gold Coast Suns", "West Coast": "West Coast Eagles", "Richmond": "Richmond Tigers", "Hawthorn": "Hawthorn Hawks", "GWS": "Greater Western Sydney Giants", "Port Adelaide": "Port Adelaide Power", "Fremantle": "Fremantle Dockers" } let matchesAndOdds = [...matches]; matches.forEach((match, i) => { matchesAndOdds[i].odds = {}; odds.forEach(odd => { if (odd.home_team === ffToOa[match.home_team] && odd.away_team === ffToOa[match.away_team]) { odd.bookmakers.forEach(bookmaker => { bookmaker.markets[0].outcomes.forEach(outcome => { matchesAndOdds[i].odds[bookmaker.title] = {}; console.log(`${i}. if (${outcome.name} === ${odd.home_team})`); console.log(`${i}. if (${outcome.name} === ${odd.away_team})`); console.log("-----------------------------------------"); if (outcome.name === odd.home_team) { console.log(`${i}. home ${bookmaker.title} ${outcome.price}`); matchesAndOdds[i].odds[bookmaker.title].home = outcome.price; console.log(matchesAndOdds[i].odds[bookmaker.title].home); } else if (outcome.name === odd.away_team) { console.log(`${i}. away ${bookmaker.title} ${outcome.price}`); matchesAndOdds[i].odds[bookmaker.title].away = outcome.price; console.log(matchesAndOdds[i].odds[bookmaker.title].away); } }) }) } }) }) console.log(matchesAndOdds)
问题根因
你的猜测完全正确,odds属性确实在循环中被意外覆盖了。
问题出在遍历outcomes的循环内部:每次处理一个胜负结果时,都会执行matchesAndOdds[i].odds[bookmaker.title] = {},将当前博彩公司对应的赔率对象重置为全新空对象。
实际执行流程:
- 处理第一个outcome(主队Brisbane Lions):先将Unibet对应的赔率对象置空,再写入
home属性值1.36,此时控制台打印正常,主队赔率确实存在 - 处理第二个outcome(客队Western Bulldogs):再次执行置空操作,直接把刚才存储了主队赔率的对象替换为空对象,再写入
away属性值3.15
循环结束后,对象中自然仅保留最后一次写入的客队赔率,之前赋值的主队数据在第二次置空时已经被删除。控制台能打印到主队赔率,是因为赋值操作完成后立刻打印,此时还未执行下一轮循环的覆盖逻辑。
修复方案
将博彩公司赔率对象的初始化逻辑,从outcomes循环内部移动到外层bookmaker循环中,每个博彩公司仅初始化一次赔率对象即可,无需在遍历每个胜负结果时重复重置。
修复后的核心循环代码:
matches.forEach((match, i) => { matchesAndOdds[i].odds = {}; odds.forEach(odd => { if (odd.home_team === ffToOa[match.home_team] && odd.away_team === ffToOa[match.away_team]) { odd.bookmakers.forEach(bookmaker => { // 初始化逻辑移到这里,每个bookmaker仅执行一次 matchesAndOdds[i].odds[bookmaker.title] = {}; bookmaker.markets[0].outcomes.forEach(outcome => { console.log(`${i}. if (${outcome.name} === ${odd.home_team})`); console.log(`${i}. if (${outcome.name} === ${odd.away_team})`); console.log("-----------------------------------------"); if (outcome.name === odd.home_team) { console.log(`${i}. home ${bookmaker.title} ${outcome.price}`); matchesAndOdds[i].odds[bookmaker.title].home = outcome.price; console.log(matchesAndOdds[i].odds[bookmaker.title].home); } else if (outcome.name === odd.away_team) { console.log(`${i}. away ${bookmaker.title} ${outcome.price}`); matchesAndOdds[i].odds[bookmaker.title].away = outcome.price; console.log(matchesAndOdds[i].odds[bookmaker.title].away); } }) }) } }) })
修改后运行,最终输出的matchesAndOdds对象会同时保留主、客队的完整赔率数据。
内容的提问来源于stack exchange,提问作者dhenry437
相关产品推荐
相关产品推荐

