如何检查一个对象的keys和deep keys是否相等,类似于lodash的isEqual?
How to check if an object's keys and deep keys are equal, similar to lodash's isEqual?
所以我处于一个独特的情况,我有两个对象,我需要比较所述对象上的键以确保它们与默认对象匹配。这是我正在尝试做的一个例子:
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;
}
让我解释一下。首先,我有一个默认对象,每次用户首次使用该服务时都会创建该对象。然后,将该对象修改为其自定义设置。例如,他们可以将 'setting1' 更改为 false,同时将 'perm2' 更改为 'ALL'.
现在,我的默认对象的旧版本曾经有一个名为 'myoldsetting' 的 属性。我不希望较新的产品具有此设置,因此每次用户请求他们的数据时,我都会检查他们的对象是否具有设置 'myoldsetting',如果有,则将其删除。然后,为了防止不必要的更新(因为每次 用户需要他们的数据时都会调用 ),我检查它是否与新的默认对象相等。
但这不起作用,因为如果用户更改了设置,它将始终 return false 并强制更新数据库,即使 none 的键已更改。要解决此问题,我需要一种方法来比较对象上的 键 ,而不是任何键和数据。
那样的话,如果我向 DefaultObject 添加一个新选项,比如 'perm5' 设置为 'ADMIN',那么它将更新用户的对象。但是,如果他们的对象具有相同的键(它是最新的),那么继续你的一天。
我需要比较深入,以防万一我在 myobj1 中添加新的 属性。如果我只比较主要级别的密钥(id、myobj1、myobj2),它不会知道我是否在 myobj1 或 myobj2 中添加了新密钥。
如果这没有意义,我深表歉意,这是一个非常特殊的情况。如果您能提供帮助,请提前致谢。
~~~~编辑~~~~
好吧,我实际上想出了一个函数,它完全可以满足我的需要。问题是,我想缩小它,让它不那么大。此外,我似乎无法找到一种方法来检查项目是否为对象,即使它为空。这个答案不是很有帮助。
这是我的工作函数。
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;
}
用法
getKeysDeep([], myobj);
是否可以在不放入空数组的情况下使用它?
所以,如果我理解正确的话,您想比较两个对象的键,对吗?
如果是这种情况,您可以尝试这样的操作:
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) 将为您提供对象自身属性的所有键。
如果值不在调用 indexOf 的数组中,indexOf 将 return 为 -1。
有些会 return 一旦数组的任何元素 (aKeys) 在回调中评估为真。在这种情况下:如果任何键未包含在另一个数组中 (indexOf(key) < 0
)
好吧,我实际上想出了一个函数,它完全可以满足我的需要。问题是,我想缩小它,让它不那么大。此外,我似乎无法找到一种方法来检查项目是否为对象,即使它为 null。
最后,这对我有用。如果有人可以改进它,那就太棒了。
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);
所以我处于一个独特的情况,我有两个对象,我需要比较所述对象上的键以确保它们与默认对象匹配。这是我正在尝试做的一个例子:
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;
}
让我解释一下。首先,我有一个默认对象,每次用户首次使用该服务时都会创建该对象。然后,将该对象修改为其自定义设置。例如,他们可以将 'setting1' 更改为 false,同时将 'perm2' 更改为 'ALL'.
现在,我的默认对象的旧版本曾经有一个名为 'myoldsetting' 的 属性。我不希望较新的产品具有此设置,因此每次用户请求他们的数据时,我都会检查他们的对象是否具有设置 'myoldsetting',如果有,则将其删除。然后,为了防止不必要的更新(因为每次 用户需要他们的数据时都会调用 ),我检查它是否与新的默认对象相等。
但这不起作用,因为如果用户更改了设置,它将始终 return false 并强制更新数据库,即使 none 的键已更改。要解决此问题,我需要一种方法来比较对象上的 键 ,而不是任何键和数据。
那样的话,如果我向 DefaultObject 添加一个新选项,比如 'perm5' 设置为 'ADMIN',那么它将更新用户的对象。但是,如果他们的对象具有相同的键(它是最新的),那么继续你的一天。
我需要比较深入,以防万一我在 myobj1 中添加新的 属性。如果我只比较主要级别的密钥(id、myobj1、myobj2),它不会知道我是否在 myobj1 或 myobj2 中添加了新密钥。
如果这没有意义,我深表歉意,这是一个非常特殊的情况。如果您能提供帮助,请提前致谢。
~~~~编辑~~~~
好吧,我实际上想出了一个函数,它完全可以满足我的需要。问题是,我想缩小它,让它不那么大。此外,我似乎无法找到一种方法来检查项目是否为对象,即使它为空。这个答案不是很有帮助。
这是我的工作函数。
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;
}
用法
getKeysDeep([], myobj);
是否可以在不放入空数组的情况下使用它?
所以,如果我理解正确的话,您想比较两个对象的键,对吗?
如果是这种情况,您可以尝试这样的操作:
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) 将为您提供对象自身属性的所有键。
如果值不在调用 indexOf 的数组中,indexOf 将 return 为 -1。
有些会 return 一旦数组的任何元素 (aKeys) 在回调中评估为真。在这种情况下:如果任何键未包含在另一个数组中 (indexOf(key) < 0
)
好吧,我实际上想出了一个函数,它完全可以满足我的需要。问题是,我想缩小它,让它不那么大。此外,我似乎无法找到一种方法来检查项目是否为对象,即使它为 null。
最后,这对我有用。如果有人可以改进它,那就太棒了。
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);