React TypeScript 按条件移除多维对象内指定数组项方案
问题背景
现有多层嵌套结构的对象,需要删除对象内数组字段中符合匹配条件的指定对象片段,匹配的唯一标识符为 "menuKey": "sidebarRewards",需要给出可落地的实现方案,同时确认是否可以通过单行数组解构的方式实现,是否存在更优解法。
待移除的目标对象片段
{ "menuKey": "sidebarRewards", "label": "Smart Rewards", "iconSetName": "narrow", "description": "", "url": "example.com/account/sidebar/index.tmpl#rewards" }
原始对象完整结构
{ "profile-welcome": { "type": "user-profile-welcome", "params": { "welcomeBack": "Welcome Back!" } }, "sidebar-tier": { "type": "user-sidebar-tier", "params": { "rewardsLink": { "label": "REWARDS", "url": "/smartrewards" } } }, "account-links": { "type": "account-links", "params": { "menu": [ { "menuKey": "sidebarAccount", "label": "My Account", "iconSetName": "narrow", "description": "", "url": "example.com/account/index.tmpl" }, { "menuKey": "sidebarSettings", "label": "Account Settings", "iconSetName": "narrow", "description": "", "url": "example.com/account/profile_preferences.tmpl" }, { "menuKey": "sidebarRewards", "label": "Smart Rewards", "iconSetName": "narrow", "description": "", "url": "example.com/account/sidebar/index.tmpl#rewards" }, { "menuKey": "sidebarSignOut", "label": "Sign Out ", "iconSetName": "narrow", "description": "", "url": "example.com/account/signin.tmpl?_SUBMIT=signout" } ] } }, "showcase": { "type": "showcase", "params": { "brandServices": { "header": "SKIN SERVICES", "infoLink": { "label": "", "url": "" }, "list": [ { "showCaseKey": "firstBrandShowcase", "title": "Skin Services.", "teaser": "Our team of Consultants is at your fingertips for tips and advice.", "label": "See All Skin Services", "url": "/services" }, { "showCaseKey": "secondBrandShowcase", "title": "Try on makeup.", "teaser": "Find your perfect shades and use your phone to try them on.", "label": "Select Makeup to Try On", "url": "/clinicalreality" } ] } } } }
实现方案
针对你的需求,分场景给对应解法:
首先明确:如果你已经知道目标数组所在的固定路径(本例中就是account-links.params.menu),完全可以用展开+解构的方式实现,不需要复杂逻辑。
- 不可变单行写法(不修改原对象,返回新对象,适合前端框架状态更新等要求不可变数据的场景)
核心就是对路径上的每一层对象做展开,最后对目标数组用filter过滤掉匹配项,全程不会改动原始对象,代码如下:
const result = {...originalObj, 'account-links': {...originalObj['account-links'], params: {...originalObj['account-links'].params, menu: originalObj['account-links'].params.menu.filter(i => i.menuKey !== 'sidebarRewards')}}}
- 直接修改原对象的极简写法(不需要保留原数据时用,代码最短)
originalObj['account-links'].params.menu = originalObj['account-links'].params.menu.filter(i => i.menuKey !== 'sidebarRewards')
执行完这行,目标项就直接从原数组里被移除了。
- 通用递归写法(如果未来对象结构可能调整,你不确定目标数组的具体嵌套层级时用)
这个方法会深度遍历整个对象的所有节点,只要是数组里存在menuKey === 'sidebarRewards'的项,都会被自动移除,不需要提前写死路径:
function deepRemoveMatch(obj, matchKey, matchVal) { if (Array.isArray(obj)) { return obj .filter(item => !(item?.[matchKey] === matchVal)) .map(item => typeof item === 'object' && item !== null ? deepRemoveMatch(item, matchKey, matchVal) : item) } if (typeof obj === 'object' && obj !== null) { return Object.fromEntries( Object.entries(obj).map(([k, v]) => [k, deepRemoveMatch(v, matchKey, matchVal)]) ) } return obj } // 调用示例 const result = deepRemoveMatch(originalObj, 'menuKey', 'sidebarRewards')
选型建议
- 固定结构的常规场景直接选第一种不可变写法就行,逻辑清晰,没有副作用,后续维护的人一眼能看懂改了什么
- 小脚本、不需要保留原对象的场景直接用第二种写法,最省事
- 只有结构动态变化、无法提前确定路径的时候再用递归方案,性能比固定路径写法稍差,但是通用性最强
内容的提问来源于stack exchange,提问作者Saravanan R
相关产品推荐
相关产品推荐

