如何检查两个对象是否具有相同的属性名称集?

dan*_*n27 52 javascript mocha.js node.js chai

我正在为我的应用程序使用node,mocha和chai.我想测试我的返回结果数据属性与我的模型对象之一是"对象类型".(与柴的实例非常相似).我只是想确认这两个对象具有相同的属性名称集.我特别对属性的实际值不感兴趣.

让我们说我有像下面的模型人.我想检查我的results.data是否具有与预期模型相同的属性.所以在这种情况下,Person具有firstName和lastName.

因此,如果results.data.lastNameresults.data.firstName同时存在,那么它应该返回true.如果其中任何一个不存在,则应返回false.如果results.data具有任何其他属性(如results.data.surname),那么它将返回false,因为在Person中不存在姓氏.

该模型

function Person(data) {
  var self = this;
  self.firstName = "unknown";
  self.lastName = "unknown";

  if (typeof data != "undefined") {
     self.firstName = data.firstName;
     self.lastName = data.lastName;
  }
}
Run Code Online (Sandbox Code Playgroud)

Cas*_*ter 87

您可以序列化简单数据以检查是否相等:

data1 = {firstName: 'John', lastName: 'Smith'};
data2 = {firstName: 'Jane', lastName: 'Smith'};
JSON.stringify(data1) === JSON.stringify(data2)
Run Code Online (Sandbox Code Playgroud)

这会给你类似的东西

'{firstName:"John",lastName:"Smith"}' === '{firstName:"Jane",lastName:"Smith"}'
Run Code Online (Sandbox Code Playgroud)

作为一个功能......

function compare(a, b) {
  return JSON.stringify(a) === JSON.stringify(b);
}
compare(data1, data2);
Run Code Online (Sandbox Code Playgroud)

编辑

如果你像你说的那样使用柴,请查看http://chaijs.com/api/bdd/#equal-section

编辑2

如果你只想检查钥匙......

function compareKeys(a, b) {
  var aKeys = Object.keys(a).sort();
  var bKeys = Object.keys(b).sort();
  return JSON.stringify(aKeys) === JSON.stringify(bKeys);
}
Run Code Online (Sandbox Code Playgroud)

应该这样做.

  • + 1的想法,但小心陷阱 - **的参数顺序是重要的**在你的方法:`JSON.stringify({B:1,一个:1})`**不同于**`JSON.stringify ({a:1,b:1})` (15认同)
  • 我不想检查属性的实际值,只检查属性名称.对困惑感到抱歉 (6认同)
  • 不适用于嵌套对象 (5认同)
  • 它今天有效,因为大多数浏览器都维护对象键的某种排序,但ecma规范不需要它,因此这段代码可能会失败. (3认同)

sch*_*her 26

2这是一个简短的ES6可变版本:

function objectsHaveSameKeys(...objects) {
   const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), []);
   const union = new Set(allKeys);
   return objects.every(object => union.size === Object.keys(object).length);
}
Run Code Online (Sandbox Code Playgroud)

一点性能测试(MacBook Pro - 2,8 GHz Intel Core i7,Node 5.5.0):

var x = {};
var y = {};

for (var i = 0; i < 5000000; ++i) {
    x[i] = i;
    y[i] = i;
}
Run Code Online (Sandbox Code Playgroud)

结果:

objectsHaveSameKeys(x, y) // took  4996 milliseconds
compareKeys(x, y)               // took 14880 milliseconds
hasSameProps(x,y)               // after 10 minutes I stopped execution
Run Code Online (Sandbox Code Playgroud)

  • 为什么我得到了反对票?请写评论,以便我改进我的答案:) (2认同)

Rag*_*kkr 11

如果要检查两个对象是否具有相同的属性名称,可以执行以下操作:

function hasSameProps( obj1, obj2 ) {
  return Object.keys( obj1 ).every( function( prop ) {
    return obj2.hasOwnProperty( prop );
  });
}

var obj1 = { prop1: 'hello', prop2: 'world', prop3: [1,2,3,4,5] },
    obj2 = { prop1: 'hello', prop2: 'world', prop3: [1,2,3,4,5] };

console.log(hasSameProps(obj1, obj2));
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您确保只检查两个对象的可迭代和可访问属性.

编辑 - 2013.04.26:

可以通过以下方式重写上一个函数:

function hasSameProps( obj1, obj2 ) {
    var obj1Props = Object.keys( obj1 ),
        obj2Props = Object.keys( obj2 );

    if ( obj1Props.length == obj2Props.length ) {
        return obj1Props.every( function( prop ) {
          return obj2Props.indexOf( prop ) >= 0;
        });
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我们检查两个对象是否具有相同数量的属性(否则对象具有相同的属性,并且我们必须返回逻辑假)然后,如果数字匹配,我们将检查它们是否具有相同的属性属性.

奖金

可能的增强可能是引入类型检查以在每个属性上强制执行匹配.

  • 该函数检查“obj1”的所有属性是否都存在于“obj2”中,因此它们具有相同的属性。但反之则不然。如果您想跳过具有不同属性数量的对象的迭代,则必须添加对两个对象中属性数量的检查,并在它们不匹配时返回逻辑 false。 (2认同)

Phi*_*son 7

如果你想像@speculees那样深入验证,这里有一个答案deep-keys(披露:我是这个小包的维护者)

// obj1 should have all of obj2's properties
var deepKeys = require('deep-keys');
var _ = require('underscore');
assert(0 === _.difference(deepKeys(obj2), deepKeys(obj1)).length);

// obj1 should have exactly obj2's properties
var deepKeys = require('deep-keys');
var _ = require('lodash');
assert(0 === _.xor(deepKeys(obj2), deepKeys(obj1)).length);
Run Code Online (Sandbox Code Playgroud)

或者chai:

var expect = require('chai').expect;
var deepKeys = require('deep-keys');
// obj1 should have all of obj2's properties
expect(deepKeys(obj1)).to.include.members(deepKeys(obj2));
// obj1 should have exactly obj2's properties
expect(deepKeys(obj1)).to.have.members(deepKeys(obj2));
Run Code Online (Sandbox Code Playgroud)


far*_*qis 5

这是上面由schirrmacher提供的函数的深度检查版本。以下是我的尝试。请注意:

  • 解决方案不检查 null 并且不是防弹的
  • 我还没有测试过它的性能。也许 Schirrmacher 或 OP 可以做到这一点并为社区分享。
  • 我不是 JS 专家:)。
function objectsHaveSameKeys(...objects) {
  const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), [])
  const union = new Set(allKeys)
  if (union.size === 0) return true
  if (!objects.every((object) => union.size === Object.keys(object).length)) return false

  for (let key of union.keys()) {
    let res = objects.map((o) => (typeof o[key] === 'object' ? o[key] : {}))
    if (!objectsHaveSameKeys(...res)) return false
  }
  return true
}
Run Code Online (Sandbox Code Playgroud)

更新1

在我的计算机上,通过跳过concat()并将密钥直接添加到Set(). Schirrmacher 对原始单级版本的相同优化也实现了约 40% 的改进。

优化的深度检查现在在性能上与优化的单级版本非常相似!

function objectsHaveSameKeysOptimized(...objects) {
  let union = new Set();
  union = objects.reduce((keys, object) => keys.add(Object.keys(object)), union);
  if (union.size === 0) return true
  if (!objects.every((object) => union.size === Object.keys(object).length)) return false

  for (let key of union.keys()) {
    let res = objects.map((o) => (typeof o[key] === 'object' ? o[key] : {}))
    if (!objectsHaveSameKeys(...res)) return false
  }
  return true
}
Run Code Online (Sandbox Code Playgroud)

性能比较

var x = {}
var y = {}
var a = {}
for (var j = 0; j < 10; ++j){
  a[j] = j
}

for (var i = 0; i < 500000; ++i) {
  x[i] = JSON.parse(JSON.stringify(a))
  y[i] = JSON.parse(JSON.stringify(a))
}

let startTs = new Date()
let result = objectsHaveSameKeys(x, y)
let endTs = new Date()
console.log('objectsHaveSameKeys = ' + (endTs - startTs)/1000)
Run Code Online (Sandbox Code Playgroud)

结果

A:递归/深度检查版本*

  1. 对象具有相同的键 = 5.185
  2. 对象具有相同密钥优化 = 0.415

B:原始非深度版本

  1. 对象具有相同密钥原始非深度 = 0.517
  2. 对象具有相同密钥原始非深度优化 = 0.342