JavaScript如何更新任意深度嵌套表单对象的对应状态属性
JavaScript 深度嵌套对象属性修改方案
需求说明
需要在JavaScript中修改深度嵌套对象的属性并返回修改后的对象,场景为渲染checkboxes(复选框),初始数据结构如下:
{ level1: { name: 'Level 1', key: 'level1', checked: false, subLevels: { level2: { name: 'Level 2', key: 'level2', checked: false, subLevels: { level3: { name: 'Level 3', key: 'level3', checked: true, }, level4: { name: 'Level 4', key: 'level4', checked: false, } } } } } }
对应渲染效果:
交互逻辑:用户点击任意复选框时,返回状态更新后的完整对象。例如点击key为level4的复选框时,期望返回结构如下(仅level4的checked属性翻转为true,其余属性不变):
{ level1: { name: 'Level 1', key: 'level1', checked: false, subLevels: { level2: { name: 'Level 2', key: 'level2', checked: false, subLevels: { level3: { name: 'Level 3', key: 'level3', checked: true, }, level4: { name: 'Level 4', key: 'level4', checked: true, } } } } } }
原有代码问题
初始实现的函数存在三个核心问题:
- 直接修改原对象,没有生成新对象,在前端框架的状态更新场景下无法触发视图刷新
- 递归传参错误:
changeVal(obj[key].subLevels)多取了一层subLevels,会导致递归跳过当前子层级 - 没有返回值,执行后无法拿到完整的更新后对象
原有问题代码如下:
function changeVal(obj, checkedKey) { for(const key in obj) { if(key === 'subLevels' && typeof obj.subLevels === 'object') { changeVal(obj[key].subLevels); } if(key === checkedKey) { obj[key].checked = !obj[key].checked; } } }
可直接使用的实现代码
采用递归+不可变更新的写法,支持任意深度嵌套,不修改原对象,执行后返回完整的新对象:
function changeVal(obj, checkedKey) { return Object.fromEntries( Object.entries(obj).map(([key, val]) => { // 匹配到目标key,翻转checked状态 if (key === checkedKey) { return [key, { ...val, checked: !val.checked }] } // 存在子层级则递归处理 if (val?.subLevels && typeof val.subLevels === 'object') { return [ key, { ...val, subLevels: changeVal(val.subLevels, checkedKey) } ] } // 非目标节点直接返回原值 return [key, val] }) ) }
用法
const updatedObj = changeVal(originObj, 'level4')
实现特性:
- 全程不修改原始输入对象,符合前端状态管理的不可变要求
- 无嵌套深度限制,任意层级的subLevels都能正确遍历
- 仅修改目标节点的checked属性,其余属性引用保持不变,性能更优
内容的提问来源于stack exchange,提问作者Frosted Cupcake
相关产品推荐
相关产品推荐

