Как определить равенство для двух объектов JavaScript? - PullRequest
547 голосов
/ 14 октября 2008

Оператор строгого равенства сообщит вам, если два объекта типов равны. Однако, есть ли способ определить, равны ли два объекта, так же, как значение хеш-кода в Java?

Вопрос переполнения стека Есть ли какая-либо функция hashCode в JavaScript? похожа на этот вопрос, но требует более академического ответа. Сценарий, приведенный выше, демонстрирует, почему это необходимо, и мне интересно, есть ли какое-нибудь эквивалентное решение .

Ответы [ 55 ]

2 голосов
/ 27 сентября 2013

Я делаю следующие предположения с этой функцией:

  1. Вы управляете объектами, которые сравниваете, и у вас есть только примитивные значения (то есть не вложенные объекты, функции и т. Д.).
  2. Ваш браузер поддерживает Object.keys .

Это следует рассматривать как демонстрацию простой стратегии.

/**
 * Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.)
 * @param {Object} object1
 * @param {Object} object2
 * @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}).
 * @returns {Boolean}
 */
function isEqual( object1, object2, order_matters ) {
    var keys1 = Object.keys(object1),
        keys2 = Object.keys(object2),
        i, key;

    // Test 1: Same number of elements
    if( keys1.length != keys2.length ) {
        return false;
    }

    // If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true.
    // keys1 = Object.keys({a:2, b:1}) = ["a","b"];
    // keys2 = Object.keys({b:1, a:2}) = ["b","a"];
    // This is why we are sorting keys1 and keys2.
    if( !order_matters ) {
        keys1.sort();
        keys2.sort();
    }

    // Test 2: Same keys
    for( i = 0; i < keys1.length; i++ ) {
        if( keys1[i] != keys2[i] ) {
            return false;
        }
    }

    // Test 3: Values
    for( i = 0; i < keys1.length; i++ ) {
        key = keys1[i];
        if( object1[key] != object2[key] ) {
            return false;
        }
    }

    return true;
}
2 голосов
/ 11 февраля 2015

Я знаю, что это немного устарело, но я бы хотел добавить решение, которое я нашел для этой проблемы. У меня был объект, и я хотел знать, когда изменились его данные. что-то похожее на Object.observe и что я сделал:

function checkObjects(obj,obj2){
   var values = [];
   var keys = [];
   keys = Object.keys(obj);
   keys.forEach(function(key){
      values.push(key);
   });
   var values2 = [];
   var keys2 = [];
   keys2 = Object.keys(obj2);
   keys2.forEach(function(key){
      values2.push(key);
   });
   return (values == values2 && keys == keys2)
}

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

1 голос
/ 07 мая 2014

Вот очень простой подход к проверке «равенства значений» объекта.

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

function isEquivalent(a, b) {
    // Create arrays of property names

    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different, objects are not equivalent

    if (aProps.length != bProps.length) {
        return false;
    }

    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];

        // If values of same property are not equal, objects are not equivalent
        if (a[propName] !== b[propName]) {
           return false;
        }
    }

    // If we made it this far, objects are considered equivalent
    return true;
}

// Outputs: true
console.log(isEquivalent(john, bobby));

Демонстрация - JSFiddle

Как вы можете видеть, чтобы проверить "равенство значений" объектов, мы, по сути, должны перебрать каждое свойство в объектах, чтобы увидеть, равны ли они. И хотя эта простая реализация работает для нашего примера, есть много случаев, которые она не обрабатывает. Например:

  • Что, если одно из значений свойства само является объектом?
  • Что, если одним из значений свойства является NaN (единственное значение в JavaScript, который не равен себе?)
  • Что если a имеет свойство со значением undefined, а b не имеет свойства это свойство (которое, таким образом, оценивается как неопределенное?)

Для надежного метода проверки «равенства значений» объектов лучше полагаться на хорошо протестированную библиотеку, которая охватывает различные граничные случаи, такие как Подчеркивание .

var john = {
    occupation: "Web Developer",
    age: 25
};

var bobby = {
    occupation: "Web Developer",
    age: 25
};

// Outputs: true
console.log(_.isEqual(john, bobby));

Демонстрация - JSFiddle

1 голос
/ 24 июля 2015

Я не эксперт по Javascript, но вот одна простая попытка решить эту проблему. Я проверяю три вещи:

  1. Это object, а также, что это не null, потому что typeof null это object.
  2. Если счетчик свойств двух объектов одинаков? Если нет, то они не равны.
  3. Перебрать свойства объекта one и проверить, имеет ли соответствующее свойство такое же значение во втором объекте.

function deepEqual (first, second) {
  // Not equal if either is not an object or is null.
  if (!isObject(first) || !isObject(second) ) return false;

  // If properties count is different
  if (keys(first).length != keys(second).length) return false;

  // Return false if any property value is different.
  for(prop in first){
    if (first[prop] != second[prop]) return false;
  }
  return true;
}

// Checks if argument is an object and is not null
function isObject(obj) {
  return (typeof obj === "object" && obj != null);
}

// returns arrays of object keys
function keys (obj) {
  result = [];
  for(var key in obj){
    result.push(key);
  }
  return result;
}

// Some test code
obj1 = {
  name: 'Singh',
  age: 20
}

obj2 = {
  age: 20,
  name: 'Singh'
}

obj3 = {
  name: 'Kaur',
  age: 19
}

console.log(deepEqual(obj1, obj2));
console.log(deepEqual(obj1, obj3));
1 голос
/ 14 октября 2008

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

Иногда используется один случай, когда два экземпляра считаются «равными», если они указывают на одно и то же место в памяти, но это не всегда то, что вы хотите. Например, если у меня есть класс Person, я мог бы рассмотреть два объекта Person «равными», если они имеют одинаковые фамилию, имя и номер социального страхования (даже если они указывают на разные места в памяти).

С другой стороны, мы не можем просто сказать, что два объекта равны, если значение каждого из их членов одинаково, поскольку иногда вы этого не хотите. Другими словами, для каждого класса разработчик класса должен определить, какие члены составляют «идентичность» объектов и разработать правильный оператор равенства (будь то путем перегрузки оператора == или метода Equals).

Сказать, что два объекта равны, если они имеют одинаковый хэш, - это единственный выход. Однако тогда вам нужно задаться вопросом, как вычисляется хеш для каждого экземпляра. Возвращаясь к приведенному выше примеру «Персона», мы могли бы использовать эту систему, если хэш рассчитывался путем просмотра значений полей «Имя», «Фамилия» и «Номер социального страхования». Кроме того, мы полагаемся на качество метода хеширования (сама по себе это огромная тема, но достаточно сказать, что не все хэши созданы равными, а неправильные методы хеширования могут привести к большему столкновений, которые в этом случае будут возвращать ложные совпадения).

1 голос
/ 30 марта 2018

Существует очень простое исправление для этого, все, что вам нужно сделать, это JSON.stringify () для обоих объектов при сравнении двух.

1 голос
/ 15 сентября 2018

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

const object = {};
JSON.stringify(object) === "{}" will pass but {} === "{}" will not
0 голосов
/ 25 августа 2012

Я написал небольшую библиотеку, которая работает на Node.js и в браузере под названием Compare.js. Он предлагает обычные операторы сравнения, такие как ==,! =,>,> =, <, <= И тождество для всех типов данных JavaScript. </p>

Например, вы можете использовать

cmp.eq(obj1, obj2);

и это проверит на равенство (используя подход глубокого равенства). В противном случае, если вы делаете

cmp.id(obj1, obj2);

будет сравниваться по ссылке, следовательно, проверять идентичность. Вы также можете использовать <и> для объектов, что означает подмножество и надмножество.

compare.js охватывает около 700 модульных тестов, поэтому, надеюсь, в нем не должно быть слишком много ошибок; -).

Вы можете найти его бесплатно на https://github.com/goloroden/compare.js, он открыт по лицензии MIT.

0 голосов
/ 20 февраля 2013

Быстрый способ определить, похожи ли два объекта, - использовать их методы toString (). Если вы проверяете объекты A и B, убедитесь, что A и B имеют значимые методы toString (), и убедитесь, что возвращаемые строки одинаковы.

Это не панацея, но иногда она может быть полезна в правильных ситуациях.

0 голосов
/ 19 апреля 2013
function isEqual(obj1, obj2){
    type1 = typeof(obj1);
    type2 = typeof(obj2);
    if(type1===type2){
        switch (type1){
            case "object": return JSON.stringify(obj1)===JSON.stringify(obj2);
            case "function": return eval(obj1).toString()===eval(obj2).toString();
            default: return obj1==obj2;
        }
    }
    return false;
}//have not tried but should work.
...