JavaScript数组与对象比较的正确姿势
原文:
https://www.cnblogs.com/-867259206/p/6795354.html
https://www.cnblogs.com/cuew1987/p/4057726.html
JS数组比较:
今天意外地发现JavaScript是不能用==或===操作符直接比较两个数组是否相等的。
alert([]==[]); // false
alert([]===[]); // false
以上两句代码都会弹出false。
因为JavaScript里面Array是对象,==或===操作符只能比较两个对象是否是同一个实例,也就是是否是同一个对象引用。目前JavaScript没有内置的操作符判断对象的内容是否相同。
但是惯性思维让人以为数组也是值,是可以比较的。
如果要比较数组是否相等,就只能遍历数组元素比较。
在网上流传很普遍的一种做法是将数组转换成字符串:
1 |
|
或
1 |
|
请不要使用这种方法。
这种方法在某些情况下是可行的,当两个数组的元素顺序相同且元素都可以转换成字符串的情况下确实可行,但是这样的代码存有隐患,比如数字被转换成字符串,数字“1”和字符串“1”会被认为相等,可能造成调试困难,不推荐使用。
在StackOverflow上有大神已经提供了正确的方法,我就做下搬运工吧:
// Warn if overriding existing method
if(Array.prototype.equals)console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array's prototype to call it on any array
Array.prototype.equals = function (array) {// if the other array is a falsy value, returnif (!array)return false;// compare lengths - can save a lot of time if (this.length != array.length)return false;for (var i = 0, l = this.length; i < l; i++) {// Check if we have nested arraysif (this[i] instanceof Array && array[i] instanceof Array) {// recurse into the nested arraysif (!this[i].equals(array[i]))return false; } else if (this[i] !== array[i]) { // Warning - two different object instances will never be equal: {x:20} != {x:20}return false; } } return true;
}
// Hide method from for-in loops
Object.defineProperty(Array.prototype, "equals", {enumerable: false});
JS对象比较:
在Javascript中相等运算包括"==","==="全等,两者不同之处,不必多数,本篇文章我们将来讲述如何判断两个对象是否相等? 你可能会认为,如果两个对象有相同的属性,以及它们的属性有相同的值,那么这两个对象就相等。那么下面我们通过一个实例来论证下:
var obj1 = {name: "Benjamin",sex : "male"
}
var obj2 = {name: "Benjamin",sex : "male"}//Outputs: falseconsole.log(obj1 == obj2);//Outputs: falseconsole.log(obj1 === obj2);
通过上面的例子可以看到,无论使用"=="还是"===",都返回false。主要原因是基本类型string,number通过值来比较,而对象(Date,Array)及普通对象通过指针指向的内存中的地址来做比较。看下面一个例子:
var obj1 = {name: "Benjamin",sex : "male"
};var obj2 = {name: "Benjamin",sex : "male"
};var obj3 = obj1;
//Outputs: trueconsole.log(obj1 == obj3);
//Outputs: trueconsole.log(obj1 === obj3);
//Outputs: falseconsole.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 namesvar aProps = Object.getOwnPropertyNames(a);var bProps = Object.getOwnPropertyNames(b);// If number of properties is different,// objects are not equivalentif (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 equivalentif (a[propName] !== b[propName]) {return false;}}// If we made it this far, objects// are considered equivalentreturn true;}var obj1 = {name: "Benjamin",sex : "male"
};var obj2 = {name: "Benjamin",sex : "male"
};//Outputs: trueconsole.log(isObjectValueEqual(obj1, obj2));
正如你所看到的,检查对象的“值相等”我们基本上是要遍历的对象的每个属性,看看它们是否相等。虽然这个简单的实现适用于我们的例子中,有很多情况下,它是不能处理。例如: 1) 如果该属性值之一本身就是一个对象吗? 2) 如果属性值中的一个是NaN(在JavaScript中,是不是等于自己唯一的价值?) 3) 如果一个属性的值为undefined,而另一个对象没有这个属性(因而计算结果为不确定?) 检查对象的“值相等”的一个强大的方法,最好是依靠完善的测试库,涵盖了各种边界情况。Underscore和Lo-Dash有一个名为_.isEqual()方法,用来比较好的处理深度对象的比较。您可以使用它们像这样:
1 2 |
|
最后附上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 NaNif (+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 memberkey = 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数组与对象比较的正确姿势相关推荐
- javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())...
javascript 数组和对象的浅度复制和深度复制 在平常我们用 '='来用一个变量引用一个数组或对象,这里是'引用'而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3, ...
- 17个实用的JavaScript数组和对象的方法
原文:Useful Javascript Array and Object Methods 作者:Robert Cooper 译者:Jim Xiao 前段时间,我收听了一个很棒的Syntax FM播客 ...
- php的对象和数组应该学js,JavaScript数组与对象的常用方法及 json 的序列化
一.JavaScript数据类型: 1- 原始类型:number(数值),string(字符串),boolean(布尔值)var age = 18; var username = "admi ...
- JavaScript 数组 函数 对象
数组 数组的概念 数组就是一组数据的集合,并且存储在单个变量名下 数组的创建方式 利用new创建数组 var 数组名 = new Array();var arr = new Array();//创建了 ...
- JavaScript 数组和对象
数组 数组:一组数据的集合,数组的每一个数据叫做一个元素 数组元素可以是任何类型,同一个数组中的不同元素可能是对象或数组 每个数组都具有一个length属性,通过该属性可以获取数组长度,并且可以给一个 ...
- int转换为char数组 java_int转换char的正确姿势
一:背景 在一个项目中,我需要修改一个全部由数字(0~9)组成的字符串的特定位置的特定数字,我采用的方式是先将字符串转换成字符数组,然后利用数组的位置来修改对应位置的值.代码开发完成之后,发现有乱码出 ...
- javascript 数组以及对象的深拷贝方法
for循环 var arr = [{name: 'jq',old: '20' },{name: 'aa',old: '18' }] var arr2=[] for(let i=0;i<arr.l ...
- JavaScript 数组拼接打印_JavaScript 数组方法
JavaScript 数组方法 JS 数组 JS 数组排序 JavaScript 数组的力量隐藏在数组方法中. 把数组转换为字符串 JavaScript 方法 toString() 把数组转换为数组值 ...
- 深入浅出 JavaScript 数组 v0.5
有一段时间不更新博客了,今天分享给大家的是一篇关于JS数组的,数组其实比较简单,但是用法非常灵活,在工作学习中应该多学,多用,这样才能领会数组的真谛. 以下知识主要参考<JS 精粹>和&l ...
最新文章
- golang import后带“_”下划线的意义
- VMware 虚拟化编程(7) — VixDiskLib 虚拟磁盘库详解之三
- intro to cs with python_CS 105 – Intro to Computing Non-Tech Spring 2019
- XGBoost 重要参数、方法、函数理解及调参思路(附例子)
- JavaScript debugger time out and defer.resolve
- android使用handler记录
- 使用Visio进行UML建模
- 面试官 | 如何优雅的设计Java 异常?
- 常用K线图(蜡烛图)基本概念
- 流程图的虚线是什么意思_这些新标识啥意思?交警教你怎么走
- 「leetcode」406.根据身高重建队列【贪心算法】详细图解
- 企业真实面试题总结(一)
- shp文件中polyline是什么_SHP文件坐标转换工具1.0版
- 在计算机上设置桌面,如何在计算机上设置动态桌面墙纸
- python人脸考勤系统_python人脸考勤系统Python3多进程 multiprocessing 模块实例详解
- scratch少儿趣味编程之让小猫原地转圈
- 岩七郎·小山馆の《圣童》章目概要
- IntelliJ IDEA 自动消除行尾空格
- 163邮箱|电子邮件注册,163邮箱如何注册申请?
- MongoDB可视化工具(免费)—MongoDB Compass