How can I do a shallow comparison of the properties of two objects with Javascript or lodash?

后端 未结 8 1891
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-01 11:31

Is there a way I can do a shallow comparison that will not go down and compare the contents of objects inside of objects in Javascript or lodash? Note that I did check lodas

相关标签:
8条回答
  • 2021-01-01 12:19
    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;
    }
    

    Notes:

    • Since this is shallow, areEqualShallow({a:{}}, {a:{}}) is false.

    • areEqualShallow({a:undefined}, {}) is false.

    • This includes any properties from the prototype.

    • This uses === comparison. I assume that is what you want. NaN === NaN is one case that may yield unexpected results. If === is not what you want, substitute with the comparison you want.


    EDIT: If the same keys are in each object, then

    function areEqualShallow(a, b) {
        for(var key in a) {
            if(a[key] !== b[key]) {
                return false;
            }
        }
        return true;
    }
    
    0 讨论(0)
  • 2021-01-01 12:20

    This is lifted from 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;
    

    I recommend copying it into your own project if you need to use it, as their README clearly states that they may remove or modify this and any other code in the lib without warning.

    0 讨论(0)
  • 2021-01-01 12:21

    Simple ES6 approach:

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

    Here I added the object keys amount equality checking for the following comparison should fail (an important case that usually does not taken into the account):

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

    2019 Update. Per Andrew Rasmussen' comment we also need to take into account undefined case. The problem with the previous approach is that the following comparison returns true:

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

    So, explicit keys existence check is needed. And it could be done with 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]
      );
    
    0 讨论(0)
  • 2021-01-01 12:23

    keeping in mind that it only for shallow and only for strings and numbers

    function equals(obj1, obj2) {
      return Object.keys(obj1)
        .concat(Object.keys(obj2))
        .every(key => {
          return obj1[key] === obj2[key];
        });
    }
    
    0 讨论(0)
  • 2021-01-01 12:25

    To do a "shallow" comparison where inherited properties should be ignored and NaN should equal NaN, the following should do the job. It checks that each object has the same own properties and that the values are === or both 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;
    }
    

    Using recent features like Object.keys to get own properties, then

    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

    With newer features, the checkProperties function can be simplified somewhat:

    0 讨论(0)
  • 2021-01-01 12:32
    const shallowEq = (a, b) =>
      [...Object.keys(a), ...Object.keys(b)].every((k) => b[k] === a[k]);
    

    If you really need to check undefined values, then this extension should satisfy @AndrewRasmussen:

    const shallowEq2 = (a, b) =>
      [...Object.keys(a), ...Object.keys(b)].every(k => b[k] === a[k] && a.hasOwnProperty(k) && b.hasOwnProperty(k)); 
    

    In most use cases you don't really need all the checks, and you only want to see if b contains everything a contains. Then an a-centric check would be really really terse:

    const shallowEq3 = (a, b) => Object.keys(a).every(k => b[k] === a[k]);
    
    0 讨论(0)
提交回复
热议问题