object/isEqual.jsjavascript
/**
* 比较两个值并处理循环引用。
* @private
*/
function equal(a, b, seen) {
if (Object.is(a, b)) return true
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false
if (a.constructor !== b.constructor) return false
if (seen.get(a) === b) return true
seen.set(a, b)
if (a instanceof Date) return a.getTime() === b.getTime()
if (a instanceof RegExp) return a.source === b.source && a.flags === b.flags
if (a instanceof Map) return a.size === b.size && [...a].every(([key, value]) => b.has(key) && equal(value, b.get(key), seen))
if (a instanceof Set) return a.size === b.size && [...a].every(value => b.has(value))
if (ArrayBuffer.isView(a)) return a.length === b.length && a.every((value, index) => Object.is(value, b[index]))
if (Array.isArray(a)) return a.length === b.length && a.every((value, index) => equal(value, b[index], seen))
const keysA = Reflect.ownKeys(a)
const keysB = Reflect.ownKeys(b)
const enumerableKeysA = keysA.filter(key => Object.prototype.propertyIsEnumerable.call(a, key))
const enumerableKeysB = keysB.filter(key => Object.prototype.propertyIsEnumerable.call(b, key))
return enumerableKeysA.length === enumerableKeysB.length && enumerableKeysA.every(key => Object.prototype.hasOwnProperty.call(b, key) && equal(a[key], b[key], seen))
}
/**
* 深度比较两个值,支持循环引用、Map、Set、Date 和 RegExp。
* @function isEqual
* @memberof module:object
* @param {*} first 第一个值
* @param {*} second 第二个值
* @returns {boolean} 两个值深度相等时为 true
*/
function isEqual(first, second) {
return equal(first, second, new Map())
}
export default isEqual