简体   繁体   中英

Comparing the keys of two JavaScript objects

I've got two sets of JavaScript objects. I want to compare object1 to object2, and then get a list of all the keys that are in object1, but not in object2. I've searching for resources to help me, but I've only ended up finding comparison functions for simple objects. The objects that I want to compare have a lot of nesting. I've included an example at the bottom.

How would I go about making a function for comparing these two objects? Is it possible to create a flexible function, that would also work if the objects were to change and contain more nesting?

const object1 = {
    "gender": "man",
    "age": 33,
    "origin": "USA",
    "jobinfo": {
        "type": "teacher",
        "school": "Wisconsin"
    },
    "children": [
        {
            "name": "Daniel",
            "age": 12,
            "pets": [
                {
                    "type": "cat", 
                    "name": "Willy",
                    "age": 2
                },
                {
                    "type": "dog", 
                    "name": "jimmie",
                    "age": 5
                }
            ]
        },
        {
            "name": "Martin",
            "age": 14,
            "pets": [
                {
                    "type": "bird", 
                    "name": "wagner",
                    "age": 12
                }
            ]
        }
    ],
    "hobbies": {
        "type": "football",
        "sponsor": {
            "name": "Pepsi",
            "sponsorAmount": 1000,
            "contact": {
                "name": "Leon",
                "age": 59,
                "children": [
                    {
                        "name": "James",
                        "pets": [
                            {
                                "type": "dog",
                                "age": 4
                            }
                        ]
                    }
                ]
            }
        }
    }
}

const object2 = {
    "gender": "man",
    "jobinfo": {
        "type": "teacher"
    },
    "children": [
        {
            "name": "Daniel",
            "age": 12,
            "pets": [
                {
                    "type": "cat", 
                    "name": "Willy",
                    "age": 2
                },
                {
                    "type": "dog", 
                    "name": "jimmie",
                    "age": 5
                }
            ]
        }
    ]
}

So what I want to achieve by comparing these two objects, is in this case to have an array return that consists of the keys that are in object1, but not object2. So the array would look something like this.

["age", "hobbies", "type", "sponsor", "name", "sponsorAmount", "contact", "name", "age", "children", "name", "pets", "type", "age"].

This is what I've gotten to so far. This is sort of working. But it's not printing out age for example, because age is a property that exists in multiple of the nested objects. jsfiddle: https://jsfiddle.net/rqdgojq2/

I've had a look at the following resources:

Complex solution using Set object and custom getAllKeyNames() recursive function to get all unique key names from specified object:

 var object1 = {"gender":"man","age":33,"origin":"USA","jobinfo":{"type":"teacher","school":"Wisconsin"},"children":[{"name":"Daniel","age":12,"pets":[{"type":"cat","name":"Willy","age":2},{"type":"dog","name":"jimmie","age":5}]},{"name":"Martin","age":14,"pets":[{"type":"bird","name":"wagner","age":12}]}],"hobbies":{"type":"football","sponsor":{"name":"Pepsi","sponsorAmount":1000,"contact":{"name":"Leon","age":59,"children":[{"name":"James","pets":[{"type":"dog","age":4}]}]}}}}, object2 = {"gender":"man","age":33,"origin":"USA","jobinfo":{"type":"teacher","school":"Wisconsin"},"children":[{"name":"Daniel","age":12,"pets":[{"type":"cat","name":"Willy","age":2},{"type":"dog","name":"jimmie","age":5}]}]}; function getAllKeyNames(o, res){ Object.keys(o).forEach(function(k){ if (Object.prototype.toString.call(o[k]) === "[object Object]") { getAllKeyNames(o[k], res); } else if (Array.isArray(o[k])) { o[k].forEach(function(v){ getAllKeyNames(v, res); }); } res.add(k); }); } var o1Keys = new Set(), o2Keys = new Set(); getAllKeyNames(object1, o1Keys); // unique keys of object1 getAllKeyNames(object2, o2Keys); // unique keys of object2 // get a list of all the keys that are in object1, but not in object2 var diff = [...o1Keys].filter((x) => !o2Keys.has(x)); console.log(diff);

Thanks for the feedback. I ended up solving it, with a lot of inspiration from Romans answer.

const compareObjects = (obj1, obj2)  => {
    function getAllKeyNames(o, arr, str){
        Object.keys(o).forEach(function(k){
            if (Object.prototype.toString.call(o[k]) === "[object Object]") {
                getAllKeyNames(o[k], arr, (str + '.' + k));
            } else if (Array.isArray(o[k])) {
                o[k].forEach(function(v){
                    getAllKeyNames(v, arr, (str + '.' + k));
                });
            }
            arr.push(str + '.' + k);
        });
    }

    function diff(arr1, arr2) {
        for(let i = 0; i < arr2.length; i++) {
            arr1.splice(arr1.indexOf(arr2[i]), 1);
        }
        return arr1;
    }

    const o1Keys = [];
    const o2Keys = [];
    getAllKeyNames(obj1, o1Keys, ''); // get the keys from schema
    getAllKeyNames(obj2, o2Keys, ''); // get the keys from uploaded file

    const missingProps = diff(o1Keys, o2Keys); // calculate differences
    for(let i = 0; i < missingProps.length; i++) {
        missingProps[i] = missingProps[i].replace('.', '');
    }
    return missingProps;
}

jsfiddle here: https://jsfiddle.net/p9Lm8b53/

You could use an object for counting.

 function getCount(object, keys, inc) { Object.keys(object).forEach(function (k) { if (!Array.isArray(object)) { keys[k] = (keys[k] || 0) + inc; if (!keys[k]) { delete keys[k]; } } if (object[k] && typeof object[k] === 'object') { getCount(object[k], keys, inc) } }); } var object1 = { gender: "man", age: 33, origin: "USA", jobinfo: { type: "teacher", school: "Wisconsin" }, children: [{ name: "Daniel", age: 12, pets: [{ type: "cat", name: "Willy", age: 2 }, { type: "dog", name: "jimmie", age: 5 }] }, { name: "Martin", age: 14, pets: [{ type: "bird", name: "wagner", age: 12 }] }], hobbies: { type: "football", sponsor: { name: "Pepsi", sponsorAmount: 1000, contact: { name: "Leon", age: 59, children: [{ name: "James", pets: [{ type: "dog", age: 4 }] }] } } } }, object2 = { gender: "man", jobinfo: { type: "teacher" }, children: [{ name: "Daniel", age: 12, pets: [{ type: "cat", name: "Willy", age: 2 }, { type: "dog", name: "jimmie", age: 5 }] }] }, count = {}; getCount(object1, count, 1); getCount(object2, count, -1); console.log(count);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

This recursive approach works best for me.

let object1 =  {
  a: 40,
  b: 80,
  c: 120,
  xa: [
    {
      xc: 12,
      xz: 12
    }
  ],
  rand: 12
};

let object2 = {
  a: 20,
  b: 30,
  c: 40,
  xa: [
    {
      xy: 12,
      xz3: 12
    }
  ]
};


function getObjDifferences(obj, obj2, propsMissing, keyName) {
  Object.keys(obj).forEach(key => {
    if(obj2[key] === undefined) {
      if(keyName.length > 0) propsMissing.push(keyName+"->"+key);
      else propsMissing.push(key)
    } else if (typeof obj[key] === 'object' && obj[key] !== null) {
      if(obj2[key] !== undefined) {
        if(keyName.length > 0) getObjDifferences(obj[key], obj2[key], propsMissing, keyName+"->"+key)
        else getObjDifferences(obj[key], obj2[key], propsMissing, key)
      } else {
        propsMissing.push(key)
      }      
    }
  })
  return propsMissing;
}

console.log(getObjDifferences(object1, object2, [], ''))
console.log(getObjDifferences(object2, object1, [], ''))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM