JavaScript比较数组
原文:Compare Arrays in JavaScript
JavaScript比较两个数组的一些技巧。
JavaScript中的数组本质是对象,因此用===
比较,只有在数组是相同引用时才会返回true
。
1 | const a = [1, 2, 3]; |
如何判断两个数组相等?相等是个棘手的问题:JavaScript标准定义了4种不同的方法,用于检查两个值是否“相等”,但都没有考虑到深入对象内部的相等。
在某些场景下,你需要尽可能精确的定义“相等”。在软件工程中,提出正确的问题往往能够得到明显的答案。
基于这些原则,本文提供了3种数组相等的定义,以及如何判断相等。
相同长度、每个值相等
比较a
和b
的一种方式,是检查a
的每个值是否严格等于b
的对应值。当数组元素都是原始类型而非对象时很容易实现的。
1 | const a = [1, 2, 3]; |
POJO的深度相等
上文的arrayEquals()
函数对原始类型值运行正常,但想要比较对象数组就麻烦了。
1 | const a = [{ answer: 42 }, { powerLevel: 9001 }]; |
考虑到对象数组的比较,一种简单的方式是用JSON.stringify()
。
1 | const a = [{ answer: 42 }, { powerLevel: 9001 }]; |
这种方式很方便,它需要很少的代码而且不会引用到外部库。但是比较JSON.stringify()
的输出,根据使用的不同,边界情况下可能会发生意外。由于undefined
不是有效的JSON值,以下数组具有相同的JSON.stringify()
输出,因为JSON.stringify()
将undefined
转换为null
。
1 | const a = [undefined]; |
使用lodash的isEqual()
除了null
和undefined
的问题,比较JSON.stringify()
的输出也没有考虑对象类型。一个对象,带有一个返回42
的toJSON()
函数,它的JSON.stringify()
输出和数值42
完全相同。
1 | const a = [{ toJSON: () => 42 }]; |
相似的,自定义对象和POJO的JSON.stringify()
也是相同的:
1 | class MyClass { |
与JSON.stringify()
不同,lodash的isEqual()
函数考虑了以上所有情况。
1 | const _ = require('lodash'); |
如果你需要比较类的对象或者其他花里胡哨的东西,lodash的isEqual()
函数是正确的方式。JSON.stringify()
对POJO而言是可用的,但是一定要考虑到undefined
和null
,而且只对可信的数据使用——toJSON()
可能造成安全漏洞。