looseEqual
栏目:
source
发布时间:2025-10-15
/**
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
*/
export function looseEqual(a: any, b: any): boolean {
if (a === b) return true
const isObjectA = isObject(a)
const isObjectB = isObject(b)
if (isObjectA && isObjectB) {
try {
const isArrayA = Array.isArray(a)
const isArrayB = Array.isArray(b)
if (isArrayA && isArrayB) {
return (
a.length === b.length &&
a.every((e: any, i: any) => {
return looseEqual(e, b[i])
})
)
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
} else if (!isArrayA && !isArrayB) {
const keysA = Object.keys(a)
const keysB = Object.keys(b)
return (
keysA.length === keysB.length &&
keysA.every(key => {
return looseEqual(a[key], b[key])
})
)
} else {
/* istanbul ignore next */
return false
}
} catch (e: any) {
/* istanbul ignore next */
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
这段代码实现了一个深度比较(deep comparison)的looseEqual
函数,用于判断两个值是否“松散相等”。以下是逐层解读:
1. 核心逻辑框架
export function looseEqual(a: any, b: any): boolean {
if (a === b) return true // 严格相等直接返回
// ...后续处理
}
第一步:优先检查a
和b
是否严格相等(包括基本类型值相等、对象引用相同)。若相等,直接返回true
。
2. 对象类型判断
const isObjectA = isObject(a)
const isObjectB = isObject(b)
通过isObject
(未在代码中定义,通常实现为o => o != null && typeof o === 'object'
)判断是否为普通对象/数组/Date
等复杂类型。
若两者都是对象,进入深度比较逻辑;若都不是对象,进入基本类型比较;否则返回false
。
3. 对象深度比较(核心)
3.1 数组比较
if (Array.isArray(a) && Array.isArray(b)) {
return a.length === b.length && a.every((e, i) => looseEqual(e, b[i]))
}
条件:两者均为数组。
逻辑:
长度必须相同;
递归比较每个元素(looseEqual(e, b[i]))
,支持嵌套数组。
3.2 Date对象比较
if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
}
条件:两者均为Date
实例。
逻辑:比较时间戳(毫秒数)是否相等。
3.3 普通对象比较
const keysA = Object.keys(a)
const keysB = Object.keys(b)
return keysA.length === keysB.length &&
keysA.every(key => looseEqual(a[key], b[key]))
条件:两者均为非数组普通对象。 逻辑: 对象的键数量必须相同; 递归比较每个键对应的值(支持嵌套对象)。
4. 非对象类型比较
return String(a) === String(b)
条件:a和b均为非对象类型(如字符串、数字等)。 逻辑:将值转为字符串后比较是否相等(例如1和'1'会被视为相等)。
5. 异常处理
try { /* ... */ } catch (e) { return false }
包裹整个对象比较逻辑,捕获可能的异常(如访问不可枚举属性、循环引用等),直接返回false
。
looseEqual({ a: { b: 1 } }, { a: { b: 1 } }) // true(嵌套对象)
looseEqual([1, [2]], [1, [2]]) // true(嵌套数组)
looseEqual(new Date(0), new Date(0)) // true(Date对象)
looseEqual(1, '1') // true(基本类型松散相等)
looseEqual(/a/, /a/)
本文地址:https://www.tides.cn/p_vue-source-looseEqual