添加两个对象而不覆盖对象 Javascript 中的键

问题描述

我有两个对象,一个主对象和一个临时对象 主人看起来像

{
    "gnome":{
        "child":{
            name:"child",race:"gnome"
        },"youngling":{
            name:"youngling",race:"gnome"
        }
    },"human":{...},...
}

温度看起来像

{
    "gnome":{
        "man":{
            name:"man",race:"gnome"
        }
}

我想要做的是将 temp 添加到 master 中

{
    "gnome":{
        "child":{...},"youngling":{...},"man":{...}
    },...
}

我现在拥有的

let obj = {}
function generateJson() {
        let race = getinput("race").value
        let name = getinput("name").value


        let temp = {}
        temp[`${race}`] = {}
        temp[`${race}`][`${name}`] = {
            name: name,race: race
        }

        obj = Object.assign(obj,temp)
}

它所做的只是清空并用临时值覆盖第一个重复键 a.e. {gnome:{man:{..}}}

这个问题早些时候被关闭了,因为它应该被 How can I merge properties of two JavaScript objects dynamically? 遗憾的是它没有,所有解决方案都覆盖了对象中的对象,我想添加到类似的键中

解决方法

根据您的示例,这应该可行

<script>
function merge_without_override(master,temp) {
    for(var key in temp) {
    if( !temp.hasOwnProperty(key) )
        continue;
    if(master[key] !== undefined) // key already exists in master.
        continue; 

        master[key] = Object.assign(temp[key]); // key doesnt exist,assign it.
  }
}

var master = {
    "gnome":{
        "child":{
            name:"child",race:"gnome"
        },"youngling":{
            name:"youngling",race:"gnome"
        }
    },"human":{}
};
var temp = {
    "gnome":{
        "man":{
            name:"man",race:"gnome"
        }
    }
};
console.log("master before merge");
console.log(master);
merge_without_override(master["gnome"],temp["gnome"]);
console.log("master after merge");
console.log(master);

</script>

输出(在 jsfiddle 中):

{
  gnome: {
    child: { ... },man: { ... },youngling: { ... }
  },human: { ... }
}

JsFiddle:https://jsfiddle.net/h10fpcx2/

,

Chris Ferdinandi 为此 here 编写了一个帮助程序;

我在下面添加了一个更新版本,但想为我对 Object.assign 最大的挫败感添加修复。

它改变了源材料。要解决此问题,您可以添加一个空对象作为 deepAssign 函数的第一个参数,或使用下面的函数 copyDeepAssign

// mutates the source material
function deepAssign(...args) {

    // Make sure there are objects to merge
    const len = args.length;
    if (len < 1) return;
    
    const main = args[0];
    if (len < 2) return main

    // Merge all objects into first
    let i = 0,curr;
    while (i < len) {
        curr = args[i];
        for (var key in curr) {
            // If it's an object,recursively merge
            // Otherwise,push to key
            if (Object.prototype.toString.call(curr[key]) === '[object Object]') {
                main[key] = deepAssign(main[key] || {},curr[key]);
            } else {
                main[key] = curr[key];
            }
        }
        i++;
    }

    return main;
}

// Doesn't mutate the source material
function copyDeepAssign(...args) {
    const base = {};
    
    return deepAssign(base,...args);
}