Ответ 1
Обновление:
В ответ на комментарии и опасения, связанные с первоначальным предложением (сравнение 2 строк JSON), вы можете использовать эту функцию:
function compareObjects(o, p)
{
var i,
keysO = Object.keys(o).sort(),
keysP = Object.keys(p).sort();
if (keysO.length !== keysP.length)
return false;//not the same nr of keys
if (keysO.join('') !== keysP.join(''))
return false;//different keys
for (i=0;i<keysO.length;++i)
{
if (o[keysO[i]] instanceof Array)
{
if (!(p[keysO[i]] instanceof Array))
return false;
//if (compareObjects(o[keysO[i]], p[keysO[i]] === false) return false
//would work, too, and perhaps is a better fit, still, this is easy, too
if (p[keysO[i]].sort().join('') !== o[keysO[i]].sort().join(''))
return false;
}
else if (o[keysO[i]] instanceof Date)
{
if (!(p[keysO[i]] instanceof Date))
return false;
if ((''+o[keysO[i]]) !== (''+p[keysO[i]]))
return false;
}
else if (o[keysO[i]] instanceof Function)
{
if (!(p[keysO[i]] instanceof Function))
return false;
//ignore functions, or check them regardless?
}
else if (o[keysO[i]] instanceof Object)
{
if (!(p[keysO[i]] instanceof Object))
return false;
if (o[keysO[i]] === o)
{//self reference?
if (p[keysO[i]] !== p)
return false;
}
else if (compareObjects(o[keysO[i]], p[keysO[i]]) === false)
return false;//WARNING: does not deal with circular refs other than ^^
}
if (o[keysO[i]] !== p[keysO[i]])//change !== to != for loose comparison
return false;//not the same value
}
return true;
}
Но во многих случаях это не должно быть сложной ИМО:
JSON.stringify(object1) === JSON.stringify(object2);
Если стробированные объекты одинаковы, их значения одинаковы.
Для полноты: JSON
просто игнорирует функции (ну, удаляет их все вместе). Это означает представление данных, а не функциональность.
Попытка сравнить 2 объекта, которые содержат только функции, приведет к true
:
JSON.stringify({foo: function(){return 1;}}) === JSON.stringify({foo: function(){ return -1;}});
//evaulutes to:
'{}' === '{}'
//is true, of course
Для глубокого сравнения объектов/функций вам придется обратиться к libs или написать свою собственную функцию и преодолеть тот факт, что объекты JS - это все ссылки, поэтому при сравнении o1 === ob2
он возвращает только true, если обе переменные указывают на один и тот же объект...
Как отметил @a-j в комментарии:
JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1});
- false
, так как обе строковые вызовы дают "{"a":1,"b":2}"
и "{"b":2,"a":1}"
соответственно. Что касается этого, вам нужно понять внутренности двигателя хрома V8. Я не эксперт, и не вдаваясь в подробности, вот что это сводится к:
Каждый объект, который создается, и каждый раз, когда он модифицируется, V8 создает новый скрытый класс С++ (сорт). Если объект X имеет свойство a
, а другой объект имеет то же свойство, оба этих объекта JS будут ссылаться на скрытый класс, который наследуется от общего скрытого класса, который определяет это свойство a
. Если два объекта имеют одни и те же базовые свойства, то все они будут ссылаться на одни и те же скрытые классы, а JSON.stringify
будет работать одинаково на обоих объектах. Это заданное (подробнее об объектах V8 здесь, если вам интересно).
Однако в примере, указанном a-j, оба объекта строятся по-разному. Как так? Ну, проще говоря, эти объекты никогда не существуют одновременно:
JSON.stringify({a: 1, b: 2})
Это вызов функции, выражение, которое необходимо разрешить для результирующего значения, прежде чем его можно сравнить с правым операндом. Второй литерал объекта еще не находится на столе.
Объект стробируется, и exoression разрешается к строковой константе. Литерал объекта не ссылается нигде и помечен для сбора мусора.
После этого правый операнд (выражение JSON.stringify({b: 2, a: 1})
) получает такое же лечение.
Все прекрасное и денди, но то, что также нужно учитывать, это то, что JS-двигатели теперь намного сложнее, чем раньше. Опять же, я не эксперт V8, но я думаю, что его правдоподобно, что a-j snippet сильно оптимизирован, поскольку код оптимизирован для:
"{"b":2,"a":1}" === "{"a":1,"b":2}"
По сути опуская вызов JSON.stringify
, и просто добавляя кавычки в нужные места. То есть, в конце концов, намного эффективнее.