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]);
  });
}
Другие вопросы по тегам