web-dev-qa-db-fra.com

Comment puis-je faire une comparaison superficielle des propriétés de deux objets avec Javascript ou lodash?

Est-il possible de faire une comparaison superficielle qui ne descendra pas et de comparer le contenu des objets à l'intérieur des objets en Javascript ou lodash? Notez que j'ai vérifié lodash, mais il semble effectuer une comparaison approfondie que je ne veux pas faire.

var a = { x: 1, y: 2}
var b = { x: 1, y: 3}

Existe-t-il un moyen, par exemple, de comparer a et b?

18
function areEqualShallow(a, b) {
    for(var key in a) {
        if(!(key in b) || a[key] !== b[key]) {
            return false;
        }
    }
    for(var key in b) {
        if(!(key in a) || a[key] !== b[key]) {
            return false;
        }
    }
    return true;
}

Remarques:

  • Puisque c'est peu profond, areEqualShallow({a:{}}, {a:{}}) est faux.

  • areEqualShallow({a:undefined}, {}) est faux.

  • Cela inclut toutes les propriétés du prototype.

  • Cela utilise la comparaison ===. Je suppose que c'est ce que vous voulez. NaN === NaN Est un cas qui peut donner des résultats inattendus. Si === N'est pas ce que vous voulez, remplacez-le par la comparaison que vous voulez.


EDIT: Si les mêmes clés sont dans chaque objet, alors

function areEqualShallow(a, b) {
    for(var key in a) {
        if(a[key] !== b[key]) {
            return false;
        }
    }
    return true;
}
20
Paul Draper

Approche ES6 simple:

const shallowCompare = (obj1, obj2) =>
  Object.keys(obj1).length === Object.keys(obj2).length &&
  Object.keys(obj1).every(key => obj1[key] === obj2[key]);

Ici, j'ai ajouté que la vérification de l'égalité du montant des clés d'objet pour la comparaison suivante devrait échouer (un cas important qui n'est généralement pas pris en compte):

shallowCompare({ x: 1, y: 3}, { x: 1, y: 3, a: 1}); // false

mise à jour 2019. Selon le commentaire d'Andrew Rasmussen, nous devons également prendre en compte le cas undefined. Le problème avec l'approche précédente est que la comparaison suivante renvoie true:

({ foo: undefined })['foo'] === ({ bar: undefined })['foo'] // true

Un contrôle explicite de l'existence des clés est donc nécessaire. Et cela pourrait être fait avec hasOwnProperty:

const shallowCompare = (obj1, obj2) =>
  Object.keys(obj1).length === Object.keys(obj2).length &&
  Object.keys(obj1).every(key => 
    obj2.hasOwnProperty(key) && obj1[key] === obj2[key]
  );
34
dhilt

en gardant à l'esprit que ce n'est que pour les chaînes peu profondes et uniquement pour les chaînes et les nombres

function equals(obj1, obj2) {
  return Object.keys(obj1)
    .concat(Object.keys(obj2))
    .every(key => {
      return obj1[key] === obj2[key];
    });
}
5
Adara Hv

Ceci est retiré de fbjs :

/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @typechecks
 *
 */

/*eslint-disable no-self-compare */

'use strict';

var hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */
function is(x, y) {
    // SameValue algorithm
    if (x === y) {
        // Steps 1-5, 7-10
        // Steps 6.b-6.e: +0 != -0
        return x !== 0 || 1 / x === 1 / y;
    } else {
        // Step 6.a: NaN == NaN
        return x !== x && y !== y;
    }
}

/**
 * Performs equality by iterating through keys on an object and returning false
 * when any key has values which are not strictly equal between the arguments.
 * Returns true when the values of all keys are strictly equal.
 */
function shallowEqual(objA, objB) {
    if (is(objA, objB)) {
        return true;
    }

    if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
        return false;
    }

    var keysA = Object.keys(objA);
    var keysB = Object.keys(objB);

    if (keysA.length !== keysB.length) {
        return false;
    }

    // Test for A's keys different from B.
    for (var i = 0; i < keysA.length; i++) {
        if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
            return false;
        }
    }

    return true;
}

module.exports = shallowEqual;

Je recommande de le copier dans votre propre projet si vous avez besoin de l'utiliser, car leur README indique clairement qu'ils peuvent supprimer ou modifier ce code et tout autre code dans la bibliothèque sans avertissement.

4
mpen

La solution de Paul Draper peut être optimisée en supprimant la comparaison lors de la deuxième passe.

function areEqualShallow(a, b) {
  for (let key in a) {
    if (!(key in b) || a[key] !== b[key]) {
      return false;
    }
  }
  for (let key in b) {
    if (!(key in a)) {
      return false;
    }
  }
  return true;
}
2
Ries Vriend

Pour faire une comparaison "superficielle" où les propriétés héritées doivent être ignorées et NaN doit être égal à NaN, ce qui suit doit faire le travail. Il vérifie que chaque objet a les mêmes propriétés et que les valeurs sont === ou les deux NaN:

function checkProperties(a, b) {
    var equal = true;

    // For each property of a
    for (var p in a) {

        // Check that it's an own property
        if (a.hasOwnProperty(p)) {

            // Check that b has a same named own property and that the values
            // are === or both are NaN
            if (!b.hasOwnProperty(p) || 
               (b[p] !== a[p] && !(typeof b[p] == 'number' && typeof a[p] == 'number' && isNaN(b[p] && isNaN(a[p]))))) {

                // If not, set equal to false
                equal = false;
            }
        }

        // If equal is false, stop processing properties
        if (!equal) break;
    }
    return equal;
}

Utiliser des fonctionnalités récentes comme Object.keys pour obtenir ses propres propriétés, puis

function checkProperties(a, b) {
  return Object.keys(a).every(function(p) {
    return b.hasOwnProperty(p) && 
           (b[p] == a[p] || (typeof a[p] == 'number' && typeof b[p] == 'number' && isNaN(b[p]) && isNaN(a[p])));
   });
}

// Compare a to b and b to a
function areEqualShallow(a, b) {
  return checkProperties(a, b) && checkProperties(b, a);
}

// Minimal testing
var a = {foo:'a', bar:2};
var b = {foo:'a', bar:2};
var c = {foo:'c', bar:2};
var d = {foo:'a', bar:2, fum:0};

console.log('a equal to b? ' + areEqualShallow(a,b)); // true
console.log('a equal to c? ' + areEqualShallow(a,c)); // false
console.log('a equal to d? ' + areEqualShallow(a,d)); // false

Avec des fonctionnalités plus récentes, la fonction checkProperties peut être quelque peu simplifiée:

1
RobG
var a = { x: 1, y: 2}
var b = { x: 1, y: 3}

function shalComp (obj1, obj2) {
 var verdict = true;
 for (var key in obj1) {
  if (obj2[key] != obj1[key]) {
   verdict = false;
  }
 }
 return verdict;
}
0
mrmaclean89