参考:lodash.isEqual | Lodash 中文文档 | Lodash 中文网 (lodashjs.com)
比较对象的键值对,都一样则为true,反之false; 若对象的属性值是引用类型,比较的是实际值不是地址(当然,若地址是一样的,那么肯定相等,return true);
思路:
默认不会比较函数
1.不是对象,直接返回比较结果,return ===
2. 地址相等的对象 return true
3. 两个都是对象||数组
(1)比较两对象keys的个数
(2)以obj1的key为基准,和obj2依次递归比较
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
// 全相等(深度)
function isEqual(obj1, obj2) {
if (!isObject(obj1) || !isObject(obj2)) {
// 值类型(注意,参与 equal 的一般不会是函数)
return obj1 === obj2
}
if (obj1 === obj2) {
return true
}
// 两个都是对象或数组,而且不相等
// 1. 先取出 obj1 和 obj2 的 keys ,比较个数
const obj1Keys = Object.keys(obj1)
const obj2Keys = Object.keys(obj2)
if (obj1Keys.length !== obj2Keys.length) {
return false
}
// 2. 以 obj1 为基准,和 obj2 一次递归比较
for (let key in obj1) {
// 比较当前 key 的 val —— 递归!!!
const res = isEqual(obj1[key], obj2[key])
if (!res) {
return false
}
}
// 3. 全相等
return true
}
以上代码存在部分bug:
-
循环引用问题
-
没有考虑Symbol作为key的情况。 这里只要使用
Object.getOwnPropertySymbols()获取Symbol keys即可 -
有着相同value的不同类型入参会被错误判断成相等的问题。 使用
Object.prototype.toString.call(a) === Object.prototype.toString.call(b)验证一下入参类型```const a = [1, 2, 3] const b = {0: 1, 1: 2, 2:3} isEqual(a, b) // 理应是false,但会得到true ``` -
对于 value 为 undefined 但 key 不同的情况的错误判断
* @param {any} a
* @param {any} b
* @return {boolean}
*/
const map = new Map() // (改进1)
function isEqual(a, b) {
// primitive Types
if (!isObject(a) || !isObject(b)) {
return a === b
}
// is same referance?
if (a === b) {
return true
}
// Optional: for different types but same primitive value
// (改进3)
if (!isSameType(a, b)) {
return false
}
// support circular reference in array and object
if (map.has(a) || map.has(b)) {
return true
}
map.set(a, b)
// support symbol as keys
// (改进2)
const aKeys = [...Object.keys(a), ...Object.getOwnPropertySymbols(a)]
const bKeys = [...Object.keys(b), ...Object.getOwnPropertySymbols(b)]
if (aKeys.length !== bKeys.length) {
return false
}
for (let i = 0; i < aKeys.length; i++) {
// (改进4)
if (aKeys[i] !== bKeys[i]) return false
const res = isEqual(a[aKeys[i]], b[bKeys[i]])
if (!res) {
return false
}
}
return true
}
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
function isSameType(a, b) {
return Object.prototype.toString.call(a) === Object.prototype.toString.call(b)
}