JavaScript变量赋值结果与预期不符的问题排查求助
问题分析与解决方案
核心问题1:所有宝可梦对象共享同一个引用
你遇到的所有宝可梦条目都显示最后一只Cinderace数据的问题,根源在于JavaScript中对象是引用类型。你在代码里一直复用同一个pokemonTemplate对象,没有为每只宝可梦创建独立的新对象副本。
看这段代码:
var blankTemplate = pokemonTemplate; // 后续直接将 pokemonTemplate 赋值给 parsedTeams 的各个位置
这里blankTemplate只是pokemonTemplate的引用,不是全新对象。每次修改pokemonTemplate的属性时,所有指向它的引用都会同步更新,最终所有位置只会保留最后一次修改的结果。
核心问题2:console.log的延迟解析特性
你提到第3行刚声明parsedTeams就打印,但结果和最终返回值一致,这是浏览器控制台的特性:console.log对于引用类型(对象/数组),显示的是你展开查看时的对象状态,不是调用console.log时的瞬时状态。当你后续修改这个对象时,控制台里的日志会跟着更新,看起来像是“提前”显示了最终结果。
修复方案
1. 为每只宝可梦创建独立的模板对象
不要复用同一个模板,每次需要新宝可梦时,通过函数生成全新的模板对象:
// 封装模板创建函数,每次调用都返回新对象 function getNewPokemonTemplate() { return { "pokemon" : "", "name" : "", "item" : "", "ability": "", "moves": { "1" : "", "2" : "", "3" : "", "4" : "" }, "nature" : "", "evs" : "", "gender" : "", "ivs" : "", "shiny" : "", "level" : "", "happiness" : "" }; }
然后在需要新宝可梦的位置替换原有的赋值:
// 替换原有的 parsedTeams[data][teamCount].team[1] = blankTemplate; parsedTeams[data][teamCount].team[1] = getNewPokemonTemplate();
2. 解决console.log的“提前显示”问题
如果想查看对象在某个时刻的真实快照,可以将对象转为JSON字符串再打印:
console.log(JSON.parse(JSON.stringify(parsedTeams)));
这样打印的是调用时的对象状态,不会随后续修改变化。
其他代码修正点
- 修复语法错误:
parsedTeams[gen][pokemonCount], pokemonTemplate = blankTemplate;中的逗号是错误写法,改为创建新模板对象的赋值 - 声明循环变量
i时加上let,避免成为全局变量 - 调整宝可梦计数逻辑,确保每只宝可梦对应到所属团队的正确位置
关键修正后的代码片段
function ParseTeams(rawTeams){ const parsedTeams = {}; // 打印对象快照,避免控制台延迟更新 console.log(JSON.parse(JSON.stringify(parsedTeams))); const rawLines = rawTeams.split("\n"); const teamTemplate = { "name" : "", "team": {} }; function getNewPokemonTemplate() { return { "pokemon" : "", "name" : "", "item" : "", "ability": "", "moves": { "1" : "", "2" : "", "3" : "", "4" : "" }, "nature" : "", "evs" : "", "gender" : "", "ivs" : "", "shiny" : "", "level" : "", "happiness" : "" }; } for(let i = 0; i < rawLines.length; i++) { let data = ""; let pokemonCount = 0; let teamCount = 1; let dataCount = 0; let nextIsMon = false; let gen, teamName; const currentLine = rawLines[i]; for(let c of currentLine) { if(c == "]" && !nextIsMon) { if(pokemonCount == 0){ if(!parsedTeams[data]){ parsedTeams[data] = {}; } // 为团队创建新模板副本 parsedTeams[data][teamCount] = {...teamTemplate}; // 为第一只宝可梦创建新对象 parsedTeams[data][teamCount].team[1] = getNewPokemonTemplate(); gen = data; data = ""; pokemonCount++; nextIsMon = true; continue; } } else if(c == "]" && nextIsMon) { // 为当前宝可梦创建新对象并赋值 parsedTeams[gen][teamCount].team[pokemonCount] = getNewPokemonTemplate(); pokemonCount++; dataCount = 1; continue; } else if(c == "|") { switch(dataCount){ case(0): parsedTeams[gen][teamCount].name = data; teamName = data; break; case(1): // 操作当前团队的当前宝可梦对象 const currentPokemon = parsedTeams[gen][teamCount].team[pokemonCount]; currentPokemon.pokemon = data; console.log(data); console.log(JSON.parse(JSON.stringify(parsedTeams[gen]))); break; // 其余case同理,都操作当前宝可梦对象而非全局模板 case(2): parsedTeams[gen][teamCount].team[pokemonCount].name = data; break; case(3): parsedTeams[gen][teamCount].team[pokemonCount].item = data; break; // ... 剩余case按此逻辑修改 default: console.log("count out of bounds"); }; dataCount++; data = ""; } else { data += c; } } pokemonCount = 0; teamCount++; data = ""; nextIsMon = false; } return parsedTeams; }
修改后每只宝可梦都是独立对象,不会互相覆盖,console.log也能正确显示瞬时状态。
内容的提问来源于stack exchange,提问作者user16268191
相关产品推荐
相关产品推荐

