• js中两个对象的比较


    代码取自于underscore.js 1.8.3的isEqual函数。

    做了一些小小的修改,主要是Function的比较修改。

    自己也加了一些代码解读。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>js中两个对象的比较</title>
        <script>
    /*
    需求难点描述:
    数组和对象,都能包含自身,还能包含其它类型。
    所以数组之间的比较,要递归。
    所以这块代码的设计是:
    不能包含自身的,先比较。
    然后是数组,对象比较。
    特别要注意的是,对象的循环引用。
    递归时,要记录递归的路径。
    */    
    function isEqual(a, b) {
      var toString = Object.prototype.toString,
        object_keys = Object.keys,
        has = function(obj, key) {
          return obj != null && hasOwnProperty.call(obj, key);
        };
        var isFunction = function(fn){
            return toString.call(fn) == '[object Function]' ? true : false;
        };    
      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).
        // 验证0===-0
        if (a === b) return a !== 0 || 1 / a === 1 / b;
        // A strict comparison is necessary because `null == undefined`.
        // null
        // 验证null == undefined
        if (a == null || b == null) return a === b;
    
        // 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]':
            // function虽然是引用,但两个内容一样的funciton应该相等。
          case '[object Function]':
            // 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
            // 验证 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;
        }
    
        var areArrays = className === '[object Array]';
        if (!areArrays) {
          if (typeof a != 'object' || typeof b != 'object') return false;
    
          // Objects with different constructors are not equivalent, but `Object`s or `Array`s
          // from different frames are.
          var aCtor = a.constructor,
            bCtor = b.constructor;
            // 判断顺序
            // 构造器一致
            // 构造器为函数
            // 拥有构造器属性
            // Function instanceof Function == true
            // Object instanceof Object == true
            // Array instanceof Array == false
          if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor &&
              isFunction(bCtor) && bCtor instanceof bCtor) && ('constructor' in a && 'constructor' in b)) {
            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`.
    
        // Initializing stack of traversed objects.
        // It's done here since we only need them for objects and arrays comparison.
        aStack = aStack || [];
        bStack = bStack || [];
        var length = aStack.length;
    
        while (length--) {
          // 递归才会走到这步 
           // Linear search. Performance is inversely proportional to the number of
          // unique nested structures.
          // 检测循环引用,参考用例如下
          /*
          var a = {
            "str":"string",
          };
          a["test"]=a;
    
          var b = {
            "str":"string",
          };
          b["test"]=b;
    
          console.log (isEqual(a,b));
          */
          if (aStack[length] === a){
              // 判断b的引用是否也循环,跳出循环引用这个坑
            return bStack[length] === b;
          } 
        }
    
        // Add the first object to the stack of traversed objects.
        // 递归压栈
        aStack.push(a);
        bStack.push(b);
    
        // Recursively compare objects and arrays.
        if (areArrays) {
          // Compare array lengths to determine if a deep comparison is necessary.
          length = a.length;
          // 数组长度比较
          if (length !== b.length) return false;
          // Deep compare the contents, ignoring non-numeric properties.
          // 递归比较
          while (length--) {
            if (!eq(a[length], b[length], aStack, bStack)) return false;
          }
        } else {
          // Deep compare objects.
          // 把对象的属性们转换成一个数组
          var keys = object_keys(a),
            key;
          length = keys.length;
          // Ensure that both objects contain the same number of properties before comparing deep equality.
          if (object_keys(b).length !== length) return false;
          while (length--) {
            // Deep compare each member
            key = keys[length];
            // b也有a一样的key,则递归
            if (!(has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
          }
        }
        // Remove the first object from the stack of traversed objects.
        // 递归出栈
        aStack.pop();
        bStack.pop();
        return true;
      };
    
      return eq(a,b);
    }
    
    var a = {
      "str":"ying",
    };
    a["test"]=a;
    
    var b = {
      "str":"ying",
    };
    b["test"]=a;
    
    console.log (isEqual(a,b));
        
        </script>
    </head>
    <body>
        
    </body>
    </html>
  • 相关阅读:
    win7系统激活最简单方法
    如何删除计算机多系统中不需要了的系统?
    SQL SERVER 中 GO 的用法2
    SQL SERVER 中 GO 的用法
    SQL SERVER中架构的理解
    linux诡异的半连接(SYN_RECV)队列长度
    skbtrace
    IO之流程与buffer 图
    MYSQL 缓存详解 [myownstars] 经典博客
    TCP 函数
  • 原文地址:https://www.cnblogs.com/samwu/p/4586217.html
Copyright © 2020-2023  润新知