简体   繁体   English

如何检查对象的键和深键是否相等,类似于lodash的isEqual?

[英]How to check if an object's keys and deep keys are equal, similar to lodash's isEqual?

So I'm in a unique situation where I have two objects, and I need to compare the keys on said objects to make sure they match the default object. 因此,我处于一个独特的情况下,我有两个对象,并且我需要比较所述对象上的键,以确保它们与默认对象匹配。 Here's an example of what I'm trying to do: 这是我要执行的操作的一个示例:

const _ = require('lodash');

class DefaultObject {
  constructor(id) {
    this.id = id;
    this.myobj1 = {
      setting1: true,
      setting2: false,
      setting3: 'mydynamicstring'
    };
    this.myobj2 = {
      perm1: 'ALL',
      perm2: 'LIMITED',
      perm3: 'LIMITED',
      perm4: 'ADMIN'
    };
  }
}

async verifyDataIntegrity(id, data) {
  const defaultData = _.merge(new DefaultObject(id));
  if (defaultData.hasOwnProperty('myoldsetting')) delete defaultData.myoldsetting;
  if (!_.isEqual(data, defaultData)) {
    await myMongoDBCollection.replaceOne({ id }, defaultData);
    return defaultData;
  } else {
    return data;
  }
}

async requestData(id) {
  const data = await myMongoDBCollection.findOne({ id });
  if (!data) data = await this.makeNewData(id);
  else data = await this.verifyDataIntegrity(id, data);
  return data;
}

Let me explain. 让我解释。 First, I have a default object which is created every time a user first uses the service. 首先,我有一个默认对象,每次用户首次使用该服务时都会创建一个默认对象。 Then, that object is modified to their customized settings. 然后,将该对象修改为其自定义设置。 For example, they could change 'setting1' to be false while changing 'perm2' to be 'ALL'. 例如,当将“ perm2”更改为“ ALL”时,他们可以将“ setting1”更改为false。

Now, an older version of my default object used to have a property called 'myoldsetting'. 现在,我的默认对象的旧版本曾经拥有一个名为“ myoldsetting”的属性。 I don't want newer products to have this setting, so every time a user requests their data I check if their object has the setting 'myoldsetting', and if it does, delete it. 我不希望较新的产品具有此设置,因此每次用户请求数据时,我都会检查其对象是否具有“ myoldsetting”设置,如果有,请将其删除。 Then, to prevent needless updates (because this is called every time a user wants their data), I check if it is equal with the new default object. 然后,为防止不必要的更新(因为每次用户需要其数据都会调用此更新),我检查它是否与新的默认对象相等。

But this doesn't work, because if the user has changed a setting, it will always return false and force a database update, even though none of the keys have changed. 但这是行不通的,因为即使用户没有更改任何键,如果用户更改了设置,它将始终返回false并强制更新数据库。 To fix this, I need a method of comparing the keys on an object, rather any the keys and data. 为了解决这个问题,我需要一种比较对象上的而不是任何键和数据的方法。

That way, if I add a new option to DefaultObject, say, 'perm5' set to 'ADMIN', then it will update the user's object. 这样,如果我向DefaultObject添加新选项,例如将'perm5'设置为'ADMIN',则它将更新用户的对象。 But, if their object has the same keys (it's up to date), then continue along your day. 但是,如果它们的对象具有相同的键(它是最新的),则可以继续进行。

I need this comparison to be deep, just in case I add a new property in, for example, myobj1. 我需要进行比较,以防万一我在例如myobj1中添加新属性。 If I only compare the main level keys (id, myobj1, myobj2), it won't know if I added a new key into myobj1 or myobj2. 如果仅比较主级键(id,myobj1,myobj2),则不会知道是否将新键添加到myobj1或myobj2中。

I apologize if this doesn't make sense, it's a very specific situation. 抱歉,这是非常特殊的情况。 Thanks in advance if you're able to help. 如果您能提供帮助,请先谢谢。

~~~~EDIT~~~~ ~~~~编辑~~~~

Alright, so I've actually come up with a function that does exactly what I need. 好吧,所以我实际上提出了一个功能,该功能完全可以满足我的需求。 The issue is, I'd like to minify it so that it's not so big. 问题是,我想缩小它,以免它不那么大。 Also, I can't seem to find a way to check if an item is a object even when it's null. 此外,即使它为null,我似乎也找不到找到检查项目是否为对象的方法。 This answer wasn't very helpful. 这个答案不是很有帮助。

Here's my working function. 这是我的工作职能。

function getKeysDeep(arr, obj) {
  Object.keys(obj).forEach(key => {
    if (typeof obj[key] === 'object') {
      arr = getKeysDeep(arr, obj[key]);
    }
  });
  arr = arr.concat(Object.keys(obj));
  return arr;
}

Usage 用法

getKeysDeep([], myobj);

Is it possible to use it without having to put an empty array in too? 是否可以使用它而不必放入空数组?

So, if I understand you correctly you would like to compare the keys of two objects, correct? 因此,如果我对您的理解正确,那么您想比较两个对象的键,对吗?

If that is the case you could try something like this: 如果是这种情况,您可以尝试如下操作:

function hasSameKeys(a, b) {
  const aKeys = Object.keys(a);
  const bKeys = Object.keys(b);
  return aKeys.length === bKeys.length && !(aKeys.some(key => bKeys.indexOf(key) < 0));
}

Object.keys(x) will give you all the keys of the objects own properties. Object.keys(x)将为您提供对象所有属性的键。

indexOf will return a -1 if the value is not in the array that indexOf is being called on. 如果值不在调用indexOf的数组中,则indexOf将返回-1。

some will return as soon as the any element of the array (aKeys) evaluates to true in the callback. 数组中的任何元素(aKeys)在回调中评估为true时,将立即返回一些。 In this case: If any of the keys is not included in the other array ( indexOf(key) < 0 ) 在这种情况下:如果另一个数组中未包含任何键( indexOf(key) < 0

Alright, so I've actually come up with a function that does exactly what I need. 好吧,所以我实际上提出了一个功能,该功能完全可以满足我的需求。 The issue is, I'd like to minify it so that it's not so big. 问题是,我想缩小它,以免它不那么大。 Also, I can't seem to find a way to check if an item is a object even when it's null. 此外,即使它为null,我似乎也找不到找到检查项目是否为对象的方法。

In the end, this works for me. 最后,这对我有用。 If anyone can improve it that'd be awesome. 如果有人可以改善它,那就太好了。

function getKeysDeep(obj, arr = []) {
  Object.keys(obj).forEach(key => {
    if (typeof obj[key] === 'object' && !Array.isArray(obj[key]) && obj[key] !== null) {
      arr = this.getKeysDeep(obj[key], arr);
    }
  });
  return arr.concat(Object.keys(obj));
}
getKeysDeep(myobj);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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