zoukankan      html  css  js  c++  java
  • Javascript 判断对象是否相等 Benjamin

    在Javascript中相等运算包括"==","==="全等,两者不同之处,不必多数,本篇文章我们将来讲述如何判断两个对象是否相等? 你可能会认为,如果两个对象有相同的属性,以及它们的属性有相同的值,那么这两个对象就相等。那么下面我们通过一个实例来论证下:

    var obj1 = {
        name: "Benjamin",
        sex : "male"
    }
    
    var obj2 = {
        name: "Benjamin",
        sex : "male"
    }
    
    //Outputs: false
    console.log(obj1 == obj2);
    
    //Outputs: false
    console.log(obj1 === obj2);

    通过上面的例子可以看到,无论使用"=="还是"===",都返回false。主要原因是基本类型string,number通过值来比较,而对象(Date,Array)及普通对象通过指针指向的内存中的地址来做比较。看下面一个例子:

    var obj1 = {
        name: "Benjamin",
        sex : "male"
    };
    
    var obj2 = {
        name: "Benjamin",
        sex : "male"
    };
    
    var obj3 = obj1;
    
    //Outputs: true
    console.log(obj1 == obj3);
    
    //Outputs: true
    console.log(obj1 === obj3);
    
    //Outputs: false
    console.log(obj2 == obj3);
    
    //Outputs: false
    console.log(obj2 === obj3);

    上例返回true,是因为obj1和ob3的指针指向了内存中的同一个地址。和面向对象的语言(Java/C++)中值传递和引用传递的概念相似。 因为,如果你想判断两个对象是否相等,你必须清晰,你是想判断两个对象的属性是否相同,还是属性对应的值是否相同,还是怎样?如果你判断两个对象的值是否相等,可以像下面这样:

    function isObjectValueEqual(a, b) {
        // Of course, we can do it use for in 
        // 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;
    }
    
    var obj1 = {
        name: "Benjamin",
        sex : "male"
    };
    
    var obj2 = {
        name: "Benjamin",
        sex : "male"
    };
    
    //Outputs: true
    console.log(isObjectValueEqual(obj1, obj2));

    正如你所看到的,检查对象的“值相等”我们基本上是要遍历的对象的每个属性,看看它们是否相等。虽然这个简单的实现适用于我们的例子中,有很多情况下,它是不能处理。例如: 1) 如果该属性值之一本身就是一个对象吗? 2) 如果属性值中的一个是NaN(在JavaScript中,是不是等于自己唯一的价值?) 3) 如果一个属性的值为undefined,而另一个对象没有这个属性(因而计算结果为不确定?) 检查对象的“值相等”的一个强大的方法,最好是依靠完善的测试库,涵盖了各种边界情况。Underscore和Lo-Dash有一个名为_.isEqual()方法,用来比较好的处理深度对象的比较。您可以使用它们像这样:

    // Outputs: true
    console.log(_.isEqual(obj1, obj2));

    最后附上Underscore中isEqual的部分源码:

      // Internal recursive comparison function for `isEqual`.
      var eq = function(a, b, aStack, bStack) {
        // Identical objects are equal. `0 === -0`, but they aren't identical.
        // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
        if (a === b) return a !== 0 || 1 / a === 1 / b;
        // A strict comparison is necessary because `null == undefined`.
        if (a == null || b == null) return a === b;
        // Unwrap any wrapped objects.
        if (a instanceof _) a = a._wrapped;
        if (b instanceof _) b = b._wrapped;
        // Compare `[[Class]]` names.
        var className = toString.call(a);
        if (className !== toString.call(b)) return false;
        switch (className) {
          // Strings, numbers, regular expressions, dates, and booleans are compared by value.
          case '[object RegExp]':
          // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
          case '[object String]':
            // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
            // equivalent to `new String("5")`.
            return '' + a === '' + b;
          case '[object Number]':
            // `NaN`s are equivalent, but non-reflexive.
            // Object(NaN) is equivalent to NaN
            if (+a !== +a) return +b !== +b;
            // An `egal` comparison is performed for other numeric values.
            return +a === 0 ? 1 / +a === 1 / b : +a === +b;
          case '[object Date]':
          case '[object Boolean]':
            // Coerce dates and booleans to numeric primitive values. Dates are compared by their
            // millisecond representations. Note that invalid dates with millisecond representations
            // of `NaN` are not equivalent.
            return +a === +b;
        }
        if (typeof a != 'object' || typeof b != 'object') return false;
        // Assume equality for cyclic structures. The algorithm for detecting cyclic
        // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
        var length = aStack.length;
        while (length--) {
          // Linear search. Performance is inversely proportional to the number of
          // unique nested structures.
          if (aStack[length] === a) return bStack[length] === b;
        }
        // Objects with different constructors are not equivalent, but `Object`s
        // from different frames are.
        var aCtor = a.constructor, bCtor = b.constructor;
        if (
          aCtor !== bCtor &&
          // Handle Object.create(x) cases
          'constructor' in a && 'constructor' in b &&
          !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
            _.isFunction(bCtor) && bCtor instanceof bCtor)
        ) {
          return false;
        }
        // Add the first object to the stack of traversed objects.
        aStack.push(a);
        bStack.push(b);
        var size, result;
        // Recursively compare objects and arrays.
        if (className === '[object Array]') {
          // Compare array lengths to determine if a deep comparison is necessary.
          size = a.length;
          result = size === b.length;
          if (result) {
            // Deep compare the contents, ignoring non-numeric properties.
            while (size--) {
              if (!(result = eq(a[size], b[size], aStack, bStack))) break;
            }
          }
        } else {
          // Deep compare objects.
          var keys = _.keys(a), key;
          size = keys.length;
          // Ensure that both objects contain the same number of properties before comparing deep equality.
          result = _.keys(b).length === size;
          if (result) {
            while (size--) {
              // Deep compare each member
              key = keys[size];
              if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
            }
          }
        }
        // Remove the first object from the stack of traversed objects.
        aStack.pop();
        bStack.pop();
        return result;
      };
    
      // Perform a deep comparison to check if two objects are equal.
      _.isEqual = function(a, b) {
        return eq(a, b, [], []);
      };

    感谢您的阅读,希望此篇文章对您有所帮助,文中不足之处欢迎批评斧正。

    转载声明:

    本文标题:Javascript 判断对象是否相等

    本文链接:http://www.zuojj.com/archives/775.html,转载请注明转自Benjamin-专注前端开发和用户体验

  • 相关阅读:
    Time Zone 【模拟时区转换】(HDU暑假2018多校第一场)
    HDU 1281 棋盘游戏 【二分图最大匹配】
    Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】
    Codeforces Round #527 (Div. 3) D2. Great Vova Wall (Version 2) 【思维】
    Codeforces Round #527 (Div. 3) D1. Great Vova Wall (Version 1) 【思维】
    Codeforces Round #528 (Div. 2, based on Technocup 2019 Elimination Round 4) C. Connect Three 【模拟】
    Avito Cool Challenge 2018 E. Missing Numbers 【枚举】
    Avito Cool Challenge 2018 C. Colorful Bricks 【排列组合】
    005 如何分析问题框架
    004 如何定义和澄清问题
  • 原文地址:https://www.cnblogs.com/cuew1987/p/4057726.html
Copyright © 2011-2022 走看看