文享日志

Underscore库的isEqual函数分析

JavaScript Underscore

发表于2017年09月18日13:44:25

0条评论 197次阅读

  var eq = function(a, b, aStack, bStack) {

    //三等走这个逻辑。有个东西特殊0和-0,是三等的。但我们认为不是相等的
    //因为1/0 ===Infinity 而1/-0===-Infinity,所以我们认为0是不等于-0的
    //注意此if是三等来判断的。能返回true,值必然相等。

    if (a === b) return a !== 0 || 1 / a === 1 / b;

    // 对undefined做了一下保障(但个人觉得上面if已经够用)

    if (a == null || b == null) return a === b;

    // 如果a或b是_的实例。比较的是其包裹_wrapped对象

    if (a instanceof _) a = a._wrapped;
    if (b instanceof _) b = b._wrapped;

    //获取a,b的类型

    var className = toString.call(a);

	//如果类型不等,直接返回false

    if (className !== toString.call(b)) return false;

	//类型相等的话,进一步,根据类型采取不同的处理

    switch (className) {
      case '[object RegExp]':
      case '[object String]':

		//正则转化成字符串来比较因为''+/a/i==='/a/i'为true的
		//字符串new String("a")===new String("a")为false,但我们认为是相等。值比较嘛。

        return '' + a === '' + b;
      case '[object Number]':
        
		//这里主要针对NaN请。NaN虽然不等于自身。但是我们认为它是值相等的
		//如果下面+a !== +a为true。说明a是NaN.+表示转化数字
		//如果+b !== +b为true说明b也是NaN,所以a,b值相等
		//如果+b !== +b为false说明b不是NaN,自然a和b不等

        if (+a !== +a) return +b !== +b;

        //如果不是NaN,也要考虑0的情况

        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
      case '[object Date]':
      case '[object Boolean]':

        //日期和布尔值也转化数字来比较。日期转化数字,得到的是毫秒数

        return +a === +b;
    }
	
    var areArrays = className === '[object Array]';

	//如果不是数组

    if (!areArrays) {

	  //只要有一个不是Object类型。则认为不等                         
  
      if (typeof a != 'object' || typeof b != 'object') return false;

      var aCtor = a.constructor, bCtor = b.constructor;
	  
	  //如果构造函数不等也返回false。但是有种情况除在外
	  //Object类型和Array的,
	  //即使属于不同iframe的,如果值一样。我们也认为是相等的
	  //不同iframe下的同样的对象 ===判断是不等的。
	  //Object instanceof Object为true的

      if (aCtor !== bCtor 
			&& !(_.isFunction(aCtor) 
				&& aCtor instanceof aCtor 
				&&_.isFunction(bCtor) 
				&& bCtor instanceof bCtor)
            && ('constructor' in a && 'constructor' in b)) {
        return false;
      }
    }
   
    aStack = aStack || [];
    bStack = bStack || [];
    var length = aStack.length;
    while (length--) {

      /**自嵌套结构判断,如下面的a
		*var a = {name : '11'};
		*a.o = a;
		*var c = a.o;
		*alert(c.name);
		*/
	  //如果a有嵌套现象,就看看b是否也有,注意a有,就返回了

      if (aStack[length] === a) return bStack[length] === b;
    }

    //如果上面while中没有进if,这里把a和b放到栈里

    aStack.push(a);
    bStack.push(b);

    // 如果是数组

    if (areArrays) {
      length = a.length;

	  //如果长度不等,直接返回false

      if (length !== b.length) return false;

      //递归比较每个元素

      while (length--) {

		//有一个元素不等,就返回false

        if (!eq(a[length], b[length], aStack, bStack)) return false;
      }
    } else {

      //如果是对象

      var keys = _.keys(a), key;
      length = keys.length;

      //看看对象的键数目是否相等,不是直接返回

      if (_.keys(b).length !== length) return false;

	  //递归比较每个属性值是否相等

      while (length--) {
        key = keys[length];

		//首先属性名称都得有,然看值是否相等,不等就返回false

        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
      }
    }

    //移除栈里最新的元素。说明这层是相等的

    aStack.pop();
    bStack.pop();
    return true;
  };

来源:

http://www.css88.com/doc/underscore/docs/underscore.html

http://www.qdfuns.com/notes/17398/a26d87c5c48225143cbcd43540e3a7a5.html



👍 0  👎 0
共有0条评论

发表新评论

提交

广告展示

腾讯云推广 阿里云推广