Chrome环境下JavaScript对象修改时出现诡异且不一致的异常
问题根源与修复方案
核心问题:浅拷贝导致的引用共享
你代码里用的{...boardMap}是浅拷贝——只复制了棋盘外层的a-h这些文件键,但每个键对应的内部rank对象(比如boardMap.a)还是和原boardMap共享引用。这意味着:
- 当你在
updateBoardMap里修改boardMapToUpdate[originFile][originRank]时,其实也在修改原boardMap里的对应位置 - 浏览器环境中存在事件循环、异步渲染等因素,可能导致原
boardMap被其他逻辑意外引用或修改,进而引发随机的棋盘异常;而Node环境是同步执行且测试用例隔离,所以没暴露这个问题
修复方案:改用深拷贝
需要确保棋盘的每一层对象都是全新的,彻底切断引用关联,有两种简单实现方式:
方式一:手动逐层拷贝
修改updateBoardMap中的拷贝逻辑,遍历每个file并拷贝其内部的rank对象:
export const updateBoardMap = ( piece: string, origin: string, dest: string, boardMap: BoardType ): BoardType => { const [originFile, originRank, destFile, destRank] = getOriginAndDestInfo(origin, dest); // 深拷贝棋盘的每一层 let boardMapToUpdate: BoardType = {}; for (const file in boardMap) { boardMapToUpdate[file] = { ...boardMap[file] }; } boardMapToUpdate[originFile][originRank] = ''; boardMapToUpdate[destFile][destRank] = piece; return boardMapToUpdate; };
方式二:使用structuredCloneAPI
利用浏览器和Node都支持的structuredClone做一键深拷贝,代码更简洁:
export const updateBoardMap = ( piece: string, origin: string, dest: string, boardMap: BoardType ): BoardType => { const [originFile, originRank, destFile, destRank] = getOriginAndDestInfo(origin, dest); // 深拷贝整个棋盘对象 let boardMapToUpdate: BoardType = structuredClone(boardMap); boardMapToUpdate[originFile][originRank] = ''; boardMapToUpdate[destFile][destRank] = piece; return boardMapToUpdate; };
额外优化
NewMove里的this.boardMap = { ...updatedBoardMap };是多余的,因为updateBoardMap已经返回了全新的对象,直接赋值即可:
private NewMove(): void { const updatedBoardMap = helpers.updateBoardMap( this.movingPiece, this.movingPiecesOrigin, this.movingPiecesDest, this.boardMap ); this.boardMap = updatedBoardMap; this.whitesTurn = !this.whitesTurn; }
内容的提问来源于stack exchange,提问作者arnab4477
相关产品推荐
相关产品推荐

