Как я могу проверить, что два объекта имеют одинаковый набор имен свойств?

Я использую node, mocha и chai для моего приложения. Я хочу проверить, что мое возвращаемое свойство данных результатов является тем же" типом объекта", что и один из моих объектов модели. (Очень похоже на пример чай). Я просто хочу подтвердить, что два объекта имеют одинаковые наборы имен свойств. меня конкретно не интересуют фактические значения свойств.

допустим у меня есть модель человека, как показано ниже. Я хочу проверить свои результаты.все данные те же свойства, что и ожидаемая модель. Итак, в этом случае человек, у которого есть имя и фамилия.

Если results.data.lastName и results.data.firstName оба существуют, тогда он должен вернуть true. Если какой-либо из них не существует, он должен вернуть false. Бонус будет, если результаты.данных имеет дополнительные свойства, такие как результаты.данные.фамилия, тогда она вернет false, потому что фамилия не существует лично.

модель

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

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

6 ответов


вы можете сериализовать простые данные, чтобы проверить равенство:

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

это даст вам что-то вроде

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

как функция...

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

редактировать

если вы используете чай, как вы говорите, проверьте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);
}

должны сделать это.


вот короткий ЕС6 вариативную версия:

function objectsHaveSameKeys(...objects):boolean {
   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);
}

немного тест производительности (MacBook Pro - 2,8 ГГц Intel Core i7, узел 5.5.0):

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

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

результаты:

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

Если вы хотите проверить, имеют ли оба объекта одинаковое имя свойств, вы можете сделать следующее:

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

таким образом, вы обязательно проверите только итерационные и доступные свойства обоих объектов.

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

таким образом, мы проверяем, что оба объекта имеют одинаковое количество свойств (в противном случае объекты не имеют одинаковое свойства, и мы должны вернуть логическое false), то, если число совпадает, мы идем, чтобы проверить, имеют ли они те же свойства.

бонус

возможным улучшением может быть введение также проверки типа для обеспечения соответствия каждому свойству.


если вы хотите глубокую проверку, как @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);

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

вот моя попытка проверки свойств JSON. Я использовал подход @casey-foster, но добавил рекурсию для более глубокой проверки. Третий параметр в функции является необязательным и используется только для тестирования.

//compare json2 to json1
function isValidJson(json1, json2, showInConsole) {

    if (!showInConsole)
        showInConsole = false;

    var aKeys = Object.keys(json1).sort();
    var bKeys = Object.keys(json2).sort();

    for (var i = 0; i < aKeys.length; i++) {

        if (showInConsole)
            console.log("---------" + JSON.stringify(aKeys[i]) + "  " + JSON.stringify(bKeys[i]))

        if (JSON.stringify(aKeys[i]) === JSON.stringify(bKeys[i])) {

            if (typeof json1[aKeys[i]] === 'object'){ // contains another obj

                if (showInConsole)
                    console.log("Entering " + JSON.stringify(aKeys[i]))

                if (!isValidJson(json1[aKeys[i]], json2[bKeys[i]], showInConsole)) 
                    return false; // if recursive validation fails

                if (showInConsole)
                    console.log("Leaving " + JSON.stringify(aKeys[i]))

            }

        } else {

            console.warn("validation failed at " + aKeys[i]);
            return false; // if attribute names dont mactch

        }

    }

    return true;

}

Если вы используете underscoreJs, вы можете просто использовать _.функции равны и он сравнивает все ключи и значения на каждом уровне иерархии, как показано ниже.

var object = {"status":"inserted","id":"5799acb792b0525e05ba074c","data":{"workout":[{"set":[{"setNo":1,"exercises":[{"name":"hjkh","type":"Reps","category":"Cardio","set":{"reps":5}}],"isLastSet":false,"index":0,"isStart":true,"startDuration":1469689001989,"isEnd":true,"endDuration":1469689003323,"speed":"00:00:01"}],"setType":"Set","isSuper":false,"index":0}],"time":"2016-07-28T06:56:52.800Z"}};

var object1 = {"status":"inserted","id":"5799acb792b0525e05ba074c","data":{"workout":[{"set":[{"setNo":1,"exercises":[{"name":"hjkh","type":"Reps","category":"Cardio","set":{"reps":5}}],"isLastSet":false,"index":0,"isStart":true,"startDuration":1469689001989,"isEnd":true,"endDuration":1469689003323,"speed":"00:00:01"}],"setType":"Set","isSuper":false,"index":0}],"time":"2016-07-28T06:56:52.800Z"}};

console.log(_.isEqual(object, object1));//return true

Если все ключи и значения для этих ключей одинаковы в обоих объектах, то он вернет true, иначе вернет false.