【问题标题】:combine 2 objects in javascript and concat values without overriding properties在 javascript 和 concat 值中组合 2 个对象而不覆盖属性
【发布时间】:2019-01-27 03:15:11
【问题描述】:

我查看了一堆关于此的帖子,但似乎没有一个能做我想做的事情,或者至少没有一个是我在搜索过程中发现的。

我有两个对象,我需要在不覆盖任何属性的情况下将它们组合起来。如果两个键相同,那么我需要连接它们的值。 示例:

const base = {
  icon: "icon--value1"
  item: "item--value"
} 

const extend = {
  icon: "icon--value2"
  item: "item--value"
  list: "list--value"
} 

组合对象

const combined = { 
  icon: "icon--value1 icon--value2"
  item: "item--value"
  list: "list--value"
}

我尝试使用 es6 赋值和 es6 解构,但它们只是覆盖了值。

 combined = {...base, ... extend}

不是我想要的结果。任何人都知道我怎样才能实现上述目标? 提前感谢您的帮助。

【问题讨论】:

    标签: javascript ecmascript-6


    【解决方案1】:

    如果您乐于使用 lodash(这也意味着不重新发明轮子),您可以使用记录在 here 中的 mergeWith() 函数。例如:

    const base = {
      icon: "icon--value1",
      item: "item--value"
    } 
    
    const extend = {
      icon: "icon--value2",
      item: "item--value",
      list: "list--value"
    } 
    
    const res = _.mergeWith(base, extend, (objVal, srcVal) => 
      objVal && objVal !== srcVal ? `${objVal} ${srcVal}` : srcVal
    )
    
    console.log(res)
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

    或者,您可以通过执行以下操作创建自己的mergeWith:

    const base = {
      icon: "icon--value1",
      item: "item--value"
    } 
    
    const extend = {
      icon: "icon--value2",
      item: "item--value",
      list: "list--value"
    } 
    
    const customMergeWith = (a, b, proc) => {
      const result = { ...a }
      Object.keys(b).forEach(k => {
        result[k] = proc(result[k], b[k])
      })
      return result
    }
    
    const res = customMergeWith(base, extend, (objVal, srcVal) => 
      objVal && objVal !== srcVal ? `${objVal} ${srcVal}` : srcVal
    )
    
    console.log(res)

    请注意,我个人更喜欢使用 lodash 版本,因为它更健壮,并且您需要担心的代码更少。如果没有必要,不要尝试重新发明轮子。


    最后,人们似乎觉得应该避免使用像 lodash 这样的库,可能是因为它们的大小。但是,您现在只能导入您需要的东西。详情见这个答案:How to Import a Single Lodash Function?

    【讨论】:

    • 我在我的项目之外尝试了你的 lodash 函数,但我似乎无法摆脱 linter 警告。 [eslint] 箭头函数在条件表达式中使用不明确。 [无混淆箭头]。
    • 感谢您对我的帖子的回答。谢谢
    • @me-me 很确定警告意味着 eslint 喜欢 (objVal, srcVal) => {return (<conditinal>) } 多于 (objVal, srcVal) => (<conditinal>)
    【解决方案2】:

    您可以使用reduce 来完成。

    这里的想法是:-

    1. 我们用两个对象的键创建了一个Set。
    2. 然后我们循环遍历键数组。对于每个键,我们在两个对象中搜索值并将它们连接起来(请记住,我们需要在这里使用||,否则如果一个对象没有属性将返回undefined,它将被添加到输出中,而不是所需)。然后我们将键和值添加到输出对象。

    const base = {icon: "icon--value1",item: "item--value"} 
    const extend = {icon: "icon--value2",item: "item--value", list: "list--value"} 
    
    let keys = [...new Set([...Object.keys(base), ...Object.keys(extend)]) ]
    
    let output = keys.reduce( (op, cur) => {
      if((base[cur] && extend[cur]) && (base[cur] !== extend[cur])){
        op[cur] = (base[cur]||'') + " " + (extend[cur]||'')
      }
      else {
        op[cur] = base[cur] || extend[cur]
      }
      return op;
    },{})
    
    console.log(output)

    另一种方法来实现我对 Set 所做的事情

    const base = {icon: "icon--value1",item: "item--value"} 
        const extend = {icon: "icon--value2",item: "item--value", list: "list--value"} 
    
    let keys = [...Object.keys(base), ...Object.keys(extend)]
    
    let uniqueKeys = Object.keys(keys.reduce((output,cur)=>{
      if( !output[cur] ){
        output[cur]=''
      }
      return output;
    },{}))
    
    let output = uniqueKeys.reduce( (op, cur) => {
      if((base[cur] && extend[cur]) && (base[cur] !== extend[cur])){
        op[cur] = (base[cur]||'') + " " + (extend[cur]||'')
      }
      else {
        op[cur] = base[cur] || extend[cur]
      }
      return op;
    },{})
    
    console.log(output)

    【讨论】:

    • 感谢 Code Maniac 不幸的是我不能使用 new Set 因为它在 IE 11 中不受支持,我需要支持它。没有新的集合我能做到吗
    • 太棒了!谢谢。
    • @CodeManiac 不错!
    • @CodeManiac 我正在为此编写一些测试,但没有看到 (base[cur]||'') 或 (extend[cur]||'') 每次都如何到达 || ' ' 陈述 ?因为 extend[cur] 和 base[cur] 总是有一个基于它上面的 if 检查的值。你能证实这一点吗?如果他们没有做任何事情,我想删除它们。
    【解决方案3】:

    对我来说,这将是最易读的处理方式......

    const base = {icon: "icon--value1",item: "item--value"} 
    const extend = {icon: "icon--value2",item: "item--value", list: "list--value"} 
    
    let keys = [...Object.keys(base), ...Object.keys(extend)]
    
    let output = keys.reduce((acc, key) => {
       if (acc[key]) return acc;
       let newVal = (
           (base[key] || "") 
          + " " 
          +(extend[key] || "")
       );
       return {...acc, [key]: newVal.trim().trimStart() };            
    },{})
    

    【讨论】:

    • 与@CodeManiacs 一样,您的回答不会产生正确的结果。
    • @MattWay 啊,你是对的。忘了那些空间。我很乐意删除我的,所以没有一堆重复,但我认为这是现在最干净的。想法?
    猜你喜欢
    • 2018-04-22
    • 2017-11-27
    • 1970-01-01
    • 2020-04-21
    • 2014-01-02
    • 1970-01-01
    • 2019-06-17
    • 2011-11-24
    • 2020-03-13
    相关资源
    最近更新 更多