代码取自于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>

js中两个对象的比较的更多相关文章

  1. 关于比较js中两个对象相等 ==

    “如果两个操作数都是对象,则比较他们是不是同一个对象(引用的对象在内存中的地址一样),如果两个操作数都指向同一个对象,则相等操作符返回true,否则,返回false”. 我做了一个例子 functio ...

  2. JS中的event 对象详解

    JS中的event 对象详解   JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...

  3. JavaScript -- 时光流逝(三):js中的 String 对象的方法

    JavaScript -- 知识点回顾篇(三):js中的 String 对象的方法 (1) anchor(): 创建 HTML 锚. <script type="text/javasc ...

  4. js中关于Blob对象的介绍与使用

    js中关于Blob对象的介绍与使用   blob对象介绍 一个 Blob对象表示一个不可变的, 原始数据的类似文件对象.Blob表示的数据不一定是一个JavaScript原生格式 blob对象本质上是 ...

  5. js中如何访问对象和数组

    js中如何访问对象和数组 一.总结 一句话总结:js访问对象点和中括号,访问数组的话就是中括号 对象 . [] 数组 [] 1.js访问对象的两种方式? . [] 可以使用下面两种方式访问对象的属性和 ...

  6. MVC中处理Json和JS中处理Json对象

    MVC中处理Json和JS中处理Json对象 ASP.NET MVC 很好的封装了Json,本文介绍MVC中处理Json和JS中处理Json对象,并提供详细的示例代码供参考. MVC中已经很好的封装了 ...

  7. js中的json对象详细介绍

    JSON一种简单的数据格式,比xml更轻巧,在JavaScript中处理JSON数据不需要任何特殊的API或工具包,下面为大家详细介绍下js中的json对象, 1.JSON(JavaScript Ob ...

  8. 关于js中两种定时器的设置及清除(转载)

    1.JS中的定时器有两种: window.setTimeout([function],[interval]) 设置一个定时器,并且设定了一个等待的时间[interval],当到达时间后,执行对应的方法 ...

  9. JavaScript -- 时光流逝(五):js中的 Date 对象的方法

    JavaScript -- 知识点回顾篇(五):js中的 Date 对象的方法 Date 对象: 用于处理日期和时间. 1. Date对象的方法 <script type="text/ ...

随机推荐

  1. error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 E:\OCX

    VC项目从VS2008迁移到VS2010编怿出错. 解决方法: 对比Framework和vs的安装目录下的cvtres.exe文件版本,删除旧版本即可 C:\Windows\Microsoft.NET ...

  2. return break continue

    return 程序返回,不再执行下面的代码(结束当前的方法 直接返回) break 跳出总上一层循环,不再执行循环(结束当前的循环体)continue 跳出本次循环,继续执行下次循环(结束正在执行的循 ...

  3. Java 如何快速序列化

    1,定义变量

  4. PostgreSQL连接python,postgresql在python 连接,创建表,创建表内容,插入操作,选择操作,更新操作,删除操作。

    安装 PostgreSQL可以用Python psycopg2模块集成. sycopg2是Python编程语言的PostgreSQL数据库的适配器. 其程序代码少,速度快,稳定.不需要单独安装这个模块 ...

  5. 学习JS中的小问题

    1.如果载入的2个js文件中有重名函数,那么调用的时候怎么分别调? 第二个文件载入无效. 2.checkbox jQuery对象的checked属性在选中时为checked,否则为undefined: ...

  6. JavaScript DOM 编程艺术(第2版)读书笔记(1)

    JavaScript 简史 JavaScript 是Netscape公司与Sun公司合作开发的.在 JavaScript 1.0发布时,Netscape Navigator主宰着浏览器市场.微软在推出 ...

  7. Java8新特性之一、时间日期API

    package com.effective.common.base.date; import java.time.Instant; import java.time.LocalDate; import ...

  8. 【转】MYSQL入门学习之九:索引的简单操作

    转载地址:http://www.2cto.com/database/201212/176772.html 一.创建索引  www.2cto.com           MYSQL常用的索引类型主要有以 ...

  9. PostgreSql安装

    官网:http://www.postgresql.org/download/linux/redhat/ 一.安装 由于我的机子是centos6.2,所以选择RedHat的. 按照官网所说的进行安装: ...

  10. SharePoint自动化系列——Add content type to list.

    转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ 将创建好的content type(若是跨web application需要事先publish c ...