JavaScript合并对象向嵌套属性新增字段的简洁实现方法
问题解答
首先明确两个核心结论:
- 你当前使用的多层对象展开写法是零依赖、兼容性最好、性能最优的无副作用实现(不会修改原
config对象),本身没有逻辑问题 - 实现该需求不是必须多次使用展开运算符,可以根据你的运行环境、项目依赖情况选择更简洁的实现方案
可选的更简洁实现方案
1. 原生深拷贝+直接赋值(适合现代运行环境)
如果你的项目不需要兼容IE、Node.js 16及以下版本,可以直接用ES2022标准自带的structuredClone做深拷贝,之后直接给嵌套属性赋值即可,完全不用写多层展开:
// 深拷贝生成独立的新对象,和原config完全无引用关联 const dynamicConfig = structuredClone(config) // 直接给目标节点新增字段,不会影响原对象 dynamicConfig.android.googleMaps.endPoint = "some-endpoint" dynamicConfig.android.googleMaps.apiKey = "some-api-key"
注意:structuredClone不支持拷贝函数、Symbol、Error实例等特殊类型,如果你的config里包含这类值不要用这个方案。
2. 自定义嵌套更新工具函数(适合兼容要求高、频繁操作嵌套对象的场景)
如果需要兼容老环境,又不想反复写多层展开,可以封装一个通用的嵌套更新工具,只会拷贝更新路径上的节点,性能和手写多层展开一致:
function assignNested(target, path, patch) { if (path.length === 0) return {...target, ...patch} const newTarget = {...target} let current = newTarget // 逐层拷贝路径上的节点,切断和原对象的引用关联 for (let i = 0; i < path.length - 1; i++) { const key = path[i] current[key] = {...current[key]} current = current[key] } // 合并目标节点的新增字段 const finalKey = path.at(-1) current[finalKey] = {...current[finalKey], ...patch} return newTarget } // 调用时只需要指定更新路径和新增字段即可,和嵌套深度无关 const dynamicConfig = assignNested(config, ['android', 'googleMaps'], { endPoint: "some-endpoint", apiKey: "some-api-key" })
3. 借助工具库实现(适合已有对应依赖的项目)
如果项目中已经引入了Lodash这类常用工具库,可以直接用内置方法简化代码,不需要自己封装逻辑:
import _ from 'lodash' // 方案A:深拷贝后直接赋值 const dynamicConfigA = _.cloneDeep(config) dynamicConfigA.android.googleMaps.endPoint = "some-endpoint" dynamicConfigA.android.googleMaps.apiKey = "some-api-key" // 方案B:递归合并对象,第一个参数传空对象避免修改原config const dynamicConfigB = _.merge({}, config, { android: { googleMaps: { endPoint: "some-endpoint", apiKey: "some-api-key" } } })
选型建议
- 如果只是单次修改这个固定路径的属性,直接用你原来写的多层展开即可,没有任何冗余问题,不需要额外引入复杂度
- 如果项目运行环境支持
structuredClone、且config里没有它不支持的特殊类型,优先选深拷贝+直接赋值的写法,代码最简洁 - 如果项目中频繁需要修改深层嵌套对象,再考虑封装工具函数或者使用Lodash的对应方法
内容的提问来源于stack exchange,提问作者Raul
相关产品推荐
相关产品推荐

