Javascript: глубокое сравнение
Я проверял этот вопрос. Javascript Deep Comparison. Решение вопроса не убедило меня, поэтому я попытался проанализировать проблему и придумал, что
var obj = {here: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: 1}));
// → false
console.log(deepEqual(obj, {here: 2}));
// → true
function deepEqual(a,b)
{
if( (typeof a == 'object' && a != null) &&
(typeof b == 'object' && b != null) )
{
var count = [0,0];
for( var key in a) count[0]++;
for( var key in b) count[1]++;
if( count[0]-count[1] != 0) {console.log('1');return false;}
for( var key in a)
{
if(!(key in b) || !deepEqual(a[key],b[key])) {console.log('2');return false;}
}
for( var key in b)
{
if(!(key in a) || !deepEqual(b[key],a[key])) {console.log('3');return false;}
}
}
console.log('a:'+a+' b:'+b);
return a===b;
}
obj === { here:2 }
Этот код не проходит последний тест ( console.log(deepEqual(obj, {here: 2}))), но логика рассмотрения объектов как абсолютно равных, если они имеют соответственно одинаковые ключи и значения, несмотря на то, что они являются разными экземплярами в памяти, не убеждает меня. Есть ли проблема с моим "решением" или ошибка заключается в предположениях упражнения? Код, указанный в вопросе, на который я ссылаюсь, действителен?
Ресурсы, которые hikinthru забыл упомянуть ( http://eloquentjavascript.net/04_data.html)
2 ответа
"Глубокое равенство", о котором идет речь в вашем вопросе, и "строгое равенство" - это две разные вещи. "Глубокое равенство" означает, как вы сказали, "равные ключи и равные ценности". "Строгое равенство" для объектов означает "один и тот же экземпляр". Строгое равенство подразумевает глубокое равенство, но объекты могут быть глубоко равными, не будучи строго равными.
Ваш код несколько неэффективен, потому что вам нужен только один цикл, но он будет работать правильно, если вы проверите a === b
в else
блок и return true
после for
петли. Это потому, что вы должны обрабатывать объекты отдельно от примитивных значений, таких как строки и числа. Ради ясности я удалил некоторые записи и постарался сохранить ваш стиль.
var obj = {here: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: 1}));
// → false
console.log(deepEqual(obj, {here: 2}));
// → true
console.log(obj === { here:2 });
// → false
function deepEqual(a,b)
{
if( (typeof a == 'object' && a != null) &&
(typeof b == 'object' && b != null) )
{
var count = [0,0];
for( var key in a) count[0]++;
for( var key in b) count[1]++;
if( count[0]-count[1] != 0) {return false;}
for( var key in a)
{
if(!(key in b) || !deepEqual(a[key],b[key])) {return false;}
}
for( var key in b)
{
if(!(key in a) || !deepEqual(b[key],a[key])) {return false;}
}
return true;
}
else
{
return a === b;
}
}
Вот глубокое сравнение, которое в дополнение к
Object
и
Array
также обрабатывает
Date
,
Set
,
Map
,
RegExp
:
export function deepEquals<T>(a: T, b: T): boolean {
if (typeof a !== 'object' || b === null) {
return a === b;
}
if (a instanceof Set) {
return b instanceof Set && deepEquals(Array.from(a), Array.from(b));
}
if (a instanceof Map) {
return (
b instanceof Map &&
deepEquals(Array.from(a.keys()), Array.from(b.keys())) &&
deepEquals(Array.from(a.values()), Array.from(b.values()))
);
}
if (a instanceof Date) {
return b instanceof Date && a.getTime() === b.getTime();
}
if (a instanceof RegExp) {
return b instanceof RegExp && a.toString() === b.toString();
}
return Object.keys(a).every(key => {
return deepEquals(a[key], b[key]);
});
}