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>
js中两个对象的比较的更多相关文章
- 关于比较js中两个对象相等 ==
“如果两个操作数都是对象,则比较他们是不是同一个对象(引用的对象在内存中的地址一样),如果两个操作数都指向同一个对象,则相等操作符返回true,否则,返回false”. 我做了一个例子 functio ...
- JS中的event 对象详解
JS中的event 对象详解 JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...
- JavaScript -- 时光流逝(三):js中的 String 对象的方法
JavaScript -- 知识点回顾篇(三):js中的 String 对象的方法 (1) anchor(): 创建 HTML 锚. <script type="text/javasc ...
- js中关于Blob对象的介绍与使用
js中关于Blob对象的介绍与使用 blob对象介绍 一个 Blob对象表示一个不可变的, 原始数据的类似文件对象.Blob表示的数据不一定是一个JavaScript原生格式 blob对象本质上是 ...
- js中如何访问对象和数组
js中如何访问对象和数组 一.总结 一句话总结:js访问对象点和中括号,访问数组的话就是中括号 对象 . [] 数组 [] 1.js访问对象的两种方式? . [] 可以使用下面两种方式访问对象的属性和 ...
- MVC中处理Json和JS中处理Json对象
MVC中处理Json和JS中处理Json对象 ASP.NET MVC 很好的封装了Json,本文介绍MVC中处理Json和JS中处理Json对象,并提供详细的示例代码供参考. MVC中已经很好的封装了 ...
- js中的json对象详细介绍
JSON一种简单的数据格式,比xml更轻巧,在JavaScript中处理JSON数据不需要任何特殊的API或工具包,下面为大家详细介绍下js中的json对象, 1.JSON(JavaScript Ob ...
- 关于js中两种定时器的设置及清除(转载)
1.JS中的定时器有两种: window.setTimeout([function],[interval]) 设置一个定时器,并且设定了一个等待的时间[interval],当到达时间后,执行对应的方法 ...
- JavaScript -- 时光流逝(五):js中的 Date 对象的方法
JavaScript -- 知识点回顾篇(五):js中的 Date 对象的方法 Date 对象: 用于处理日期和时间. 1. Date对象的方法 <script type="text/ ...
随机推荐
- linux设备驱动归纳总结(五):1.在内核空间分配内存【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-79134.html linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxx ...
- semantic-ui and IE only message
<![if !IE]> <div class="ui message red"> <i class="close icon"> ...
- c++ 程序在内存中的分布
从低地址到高地址: 1.代码区[包含常量的]:存放函数体的二进制代码 2.全局变量区[已初始化 + 未初始化]: 全局变量和静态变量的存储是放一块的,初始化的全局变量和静态变量在一块区域, 未初始化的 ...
- 3.1将AngularJS放入上下文
本章,作者将AngularJS放在全球web app开发的上下文里,并为后面的章节设置功能.AngularJS的目标,是带来一款工具,它有服务端开发web client的能力,并易于开发,测试,富.复 ...
- struts2的两个核心配置文件
struts2的两个核心配置文件,即:struts.default.xml和struts.properties A,位置:都在struts2-core-version.jar文件中 B,作用,stru ...
- Android 仿美团网,大众点评购买框悬浮效果之修改版
转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17761431),请尊重他人的辛勤劳动成果,谢谢! 我之前写 ...
- XCode5 真机调试及发布应用
一.XCODE 真机测试 Xcode5已经很智能,只需生成一个开发证书,安装后,插入设备会自动添加,注意,当Mac系统升级后,证书需要重新生成. 证书生成步骤: 1.生成 CertificateSig ...
- 【PHP操作sphinx】
[index.php] [find.php] <?php header("Content-type:text/html;charset=utf-8"); $keyword = ...
- C#:数据交互
JS与Web交互:http://www.docin.com/p-76710976.html 一.WinForm的WebBrowser控件与JS交互数据: 1.C#类内的代码执行JS脚本函数: 给C#类 ...
- 对Discuz的简单认识
Discuz是php的一个开源论坛系统,是由康盛创想公司2004开发,从Discuz! 1.0到 现在的Discuz X3,无论从功能上还是从用户体验上,都达到了一个质的飞越.主要包括论坛.门户.群组 ...