web-dev-qa-db-fra.com

Comment puis-je vérifier que deux objets ont le même ensemble de noms de propriétés?

J'utilise noeud, moka et chai pour mon application. Je souhaite tester que la propriété de données de résultats renvoyée est le même "type d'objet" que l'un de mes objets de modèle. (Très semblable à l'instance de chai). Je veux juste confirmer que les deux objets ont les mêmes ensembles de noms de propriété. les valeurs réelles des propriétés ne m'intéressent pas spécifiquement.

Disons que j'ai la personne modèle comme ci-dessous. Je souhaite vérifier que mes résultats.data ont toutes les mêmes propriétés que le modèle attendu. Donc, dans ce cas, une personne qui a un prénom et un nom.

Donc si results.data.lastName et results.data.firstName _ les deux existent, alors il devrait retourner vrai. Si l'un ou l'autre n'existe pas, il devrait retourner false. Un bonus serait si results.data a des propriétés supplémentaires comme results.data.surname, alors il renverrait false car le nom de famille n'existe pas dans Person.

le modèle

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

  if (typeof data != "undefined") {
     self.firstName = data.firstName;
     self.lastName = data.lastName;
  }
}
49
dan27

Vous pouvez sérialiser des données simples pour vérifier l’égalité:

data1 = {firstName: 'John', lastName: 'Smith'};
data2 = {firstName: 'Jane', lastName: 'Smith'};
JSON.stringify(data1) === JSON.stringify(data2)

Cela vous donnera quelque chose comme

'{firstName:"John",lastName:"Smith"}' === '{firstName:"Jane",lastName:"Smith"}'

En tant que fonction...

function compare(a, b) {
  return JSON.stringify(a) === JSON.stringify(b);
}
compare(data1, data2);

MODIFIER

Si vous utilisez le chai comme vous le dites, consultez http://chaijs.com/api/bdd/#equal-section

EDIT 2

Si vous voulez juste vérifier les clés ...

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

devrait le faire.

84
Casey Foster

2 Voici une version courte ES6 variadic:

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);
}

Un peu test de performance (MacBook Pro - Intel Core i7 cadencé à 2,8 GHz, Node 5.5.0):

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

for (var i = 0; i < 5000000; ++i) {
    x[i] = i;
    y[i] = i;
}

Résultats:

objectsHaveSameKeys(x, y) // took  4996 milliseconds
compareKeys(x, y)               // took 14880 milliseconds
hasSameProps(x,y)               // after 10 minutes I stopped execution
22
schirrmacher

Si vous voulez vérifier si les deux objets ont le même nom de propriétés, procédez comme suit:

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));

De cette manière, vous ne pouvez vérifier que les propriétés itérables et accessibles des deux objets.

EDIT - 2013.04.26:

La fonction précédente peut être réécrite de la manière suivante:

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;
}

De cette façon, nous vérifions que les deux objets ont le même nombre de propriétés (sinon, ils n'ont pas les mêmes propriétés et nous devons renvoyer un false logique), puis, si le nombre correspond, nous allons vérifier s'ils ont les mêmes propriétés. Propriétés.

Bonus

Une amélioration possible pourrait consister à introduire également une vérification de type pour appliquer la correspondance sur chaque propriété.

9
Ragnarokkr

Si vous voulez une validation approfondie comme @speculees, voici une réponse en utilisant deep-keys (divulgation: je suis en quelque sorte un mainteneur de ce petit paquet)

// 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);

ou avec 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));
7
Philip Garrison