Как я могу проверить, что два объекта имеют одинаковый набор имен свойств?
Я использую узел, мокко и чай для моего приложения. Я хочу проверить, что мое возвращенное свойство данных результатов является тем же "типом объекта", что и один из моих объектов модели (очень похоже на экземпляр chai). Я просто хочу подтвердить, что два объекта имеют одинаковые наборы имен свойств. Меня особо не интересуют фактические значения свойств.
Допустим, у меня есть модель Person, как показано ниже. Я хочу проверить, что мой файл results.data имеет те же свойства, что и ожидаемая модель. Таким образом, в этом случае, Person, который имеет firstName и lastName.
Таким образом, если results.data.lastName
и results.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;
}
}
Ответы
Ответ 1
Вы можете сериализовать простые данные для проверки равенства:
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);
ИЗМЕНИТЬ
Если вы используете chai, как вы говорите, посмотрите http://chaijs.com/api/bdd/#equal-section
EDIT 2
Если вы просто хотите проверить ключи...
function compareKeys(a, b) {
var aKeys = Object.keys(a).sort();
var bKeys = Object.keys(b).sort();
return JSON.stringify(aKeys) === JSON.stringify(bKeys);
}
должен это сделать.
Ответ 2
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);
}
Небольшой тест производительности (MacBook Pro - Intel Core i7 с частотой 2,8 ГГц, Node 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
Ответ 3
Если вы хотите проверить, имеют ли оба объекта одинаковое имя свойства, вы можете сделать это:
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), тогда, если число соответствует, мы переходим к проверке, если они имеют те же свойства.
Bonus
Возможным усилением может быть введение проверки типа для обеспечения соответствия каждому свойству.
Ответ 4
Если вам нужна глубокая проверка, например @speculees, вот ответ, используя deep-keys
(раскрытие: я являюсь помощником этого небольшого пакета)
// obj1 should have all of obj2 properties
var deepKeys = require('deep-keys');
var _ = require('underscore');
assert(0 === _.difference(deepKeys(obj2), deepKeys(obj1)).length);
// obj1 should have exactly obj2 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 properties
expect(deepKeys(obj1)).to.include.members(deepKeys(obj2));
// obj1 should have exactly obj2 properties
expect(deepKeys(obj1)).to.have.members(deepKeys(obj2));
Ответ 5
Вот моя попытка проверить свойства 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;
}
Ответ 6
Если вы используете underscoreJs, вы можете просто использовать функцию _.isEqual
и он сравнивает все ключи и значения на каждом уровне иерархии, как показано ниже.
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.