合并对象更新重复键(不区分大小写)

Merge objects updating duplicate keys (case-insensitively)

我正在使用具有配置对象的 javascript 模块。一个已经设置了默认值,用户可以传入值来覆盖这些设置值。我正在使用 Object.assign 合并两个对象。

这是一个例子:

const target = { a: 1, b: 2 }; // <-- default config
const source = { B: 4, c: 5 }; // <-- User input config 

Object.assign(target, source);

console.log(target); //{a: 1, b: 2, B: 4, c: 5}

在此示例中,如果用户不小心输入了大写字母 'B' 而不是小写字母,那么配置对象会为其自身添加另一个值,而我真正想要的是小写字母 'b'更新。 我知道这是 Object.assign 的预期行为,但试图让用户更容易做到这一点并且不区分大小写。

您必须先将对象键小写,就像完成的那样here

const target = { a: 1, b: 2 }; // <-- default config
const source = { B: 4, c: 5 }; // <-- User input config 

const lowerSource = Object.keys(source).reduce((c, k) => (c[k.toLowerCase()] = source[k], c), {});

Object.assign(target, lowerSource);

console.log(target);

您可以简单地重新映射 source 对象,将其键小写为 Object.keys() and Array.prototype.map(), then pass resulting key-value pairs as parameter to Object.assign():

const target = { a: 1, b: 2 },
      source = { B: 4, c: 5 },
      
      result = Object.assign(
        target, 
        ...Object
          .keys(source)
          .map(key => 
            ({[key.toLowerCase()]: source[key]}))
      )
      
console.log(result)

您可以尝试类似下面的代码。

target = { a: 1, b: 2 }; // <-- default config
source = { B: 4, c: 5 }; // <-- User input config 

source = JSON.parse(JSON.stringify(source).toLowerCase())

Object.assign(target, source);

这个版本与其他版本略有不同。它仅规范化在初始对象中找到的键,而其他键保持不变。像这样:

insensitiveAssign ({a: 1, b: 2}, {B: 4, c: 5, D: 6}) //=> {a: 1, b: 4, c: 5, D: 6}
//                                                         ^     ^     ^     ^
//                                 unaltered --------------'     |     |     |
//                                 overwritten ------------------+     |     |
//                                 added ------------------------------+     |
//                                 added (note: key not modified) -----------+

这可能对您有用,也可能没有用,但这是解决问题的有趣方法。它也不会修改您的任何一个对象,而是创建一个更改的克隆。

const insensitiveAssign = (target, source) => {
  const keys = Object .keys (target) .reduce ((a, k) => ((a[k.toLowerCase()] = k), a), {})
  return Object .entries (source) .reduce ((a, [k, v]) => {
    const lowerK = k.toLowerCase()
    const key = lowerK in keys ? keys[lowerK] : k
    a[key] = v;
    return a
  }, Object.assign({}, target)) // start with a shallow copy
}

  
const target = {a: 1, b: 2};
const source = {B: 4, c: 5, D: 6}; 

console .log (
  'result:',
  insensitiveAssign (target, source),
)
console .log (
  'target:', 
  target,
)
console .log (
  'source:',
  source
)

更新

评论更新了问题,询问如何将其应用于嵌套对象。实际上,我可能会尝试从头开始写,但我现在没有时间,对此进行修改(仅略微测试)似乎可行:

const insensitiveAssign = (target, source) => {
  // if-block added
  if (Object(target) !== target || (Object(source) !== source)) {
    return source
  }
  const keys = Object .keys (target) .reduce ((a, k) => ((a[k.toLowerCase()] = k), a), {})
  return Object .entries (source) .reduce ((a, [k, v]) => {
    const lowerK = k.toLowerCase()
    const key = lowerK in keys ? keys[lowerK] : k
    a[key] = insensitiveAssign(target[key], v); // this line updated
    return a
  }, Object.assign({}, target))
}

  
const target = {a: 1, b: 2, x: {w: 'a', y: {z: 42}}};
const source = {B: 4, c: 5, D: 6, x: {V: 'c', Y: {z: 101}}}; 

console .log (
  'result:',
  insensitiveAssign (target, source),
)
console .log (
  'target:', 
  target,
)
console .log (
  'source:',
  source
)