覆写多维数组配置时根键被替换,如何仅更新深层指定属性
问题核心原因
Object.assign 属于浅合并方法,仅会处理对象的第一层键值对,当某个键对应的值是引用类型(对象、数组)时,会直接用传入的新值覆盖原有值,不会深入子层级做合并操作,这就是你现在整个layouts配置被替换的原因。
解决方案
方案1:无第三方依赖,手动实现递归深合并
写一个通用的深合并函数,只在两个值都是纯对象时递归合并,其余情况直接用自定义配置的值覆盖:
function deepMerge(target, source) { // 遍历源对象的所有键 for (const key in source) { // 仅处理源对象自身的属性 if (source.hasOwnProperty(key)) { // 如果目标对象、源对象当前键的值都是非数组的纯对象,就递归合并 if ( typeof target[key] === 'object' && target[key] !== null && typeof source[key] === 'object' && source[key] !== null && !Array.isArray(target[key]) && !Array.isArray(source[key]) ) { deepMerge(target[key], source[key]); } else { // 其他情况直接覆盖 target[key] = source[key]; } } } return target; }
使用时替换原来的Object.assign即可:
// 建议先拷贝一份默认配置,避免污染原始默认值 this.settings = deepMerge({...this.defaultSettings}, custom.data.settings);
用你给出的示例测试,合并后layouts.root的原有配置会完整保留,仅layouts.results.view会被更新为Special,符合需求。
方案2:项目已引入Lodash时直接使用现有方法
如果你的项目已经依赖Lodash,直接调用_.merge方法即可,无需自己写工具函数:
import _ from 'lodash'; this.settings = _.merge({}, this.defaultSettings, custom.data.settings);
如果有自定义数组合并的需求,可以使用_.mergeWith自定义合并规则。
注意事项
- 调用合并前要校验接口返回的自定义配置合法性,避免返回null/非对象值导致合并报错
- 如果配置中包含Date、RegExp等特殊引用类型,需要在深合并函数中补充对应类型判断,保证合并逻辑符合预期
- 不要直接修改默认配置的原始对象,合并时第一个参数传入空对象或者默认配置的拷贝,避免原始默认值被污染
内容的提问来源于stack exchange,提问作者Martyn Ball
相关产品推荐
相关产品推荐

