UNPKG

@msom/common

Version:

@msom/common

102 lines (91 loc) 2.88 kB
import { isArray } from "../array"; /** * 比较两个对象是否相等 * 支持深度比较对象的所有属性 * * @template T 对象类型 * @param obj1 第一个对象 * @param obj2 第二个对象 * @returns 如果对象相等返回true,否则返回false * * @example * const a = { x: 1, y: { z: 2 } }; * const b = { x: 1, y: { z: 2 } }; * compareObjects(a, b); // 返回 true * * // 数组比较 * compareObjects([1], {'0': 1}); // 返回 false */ export function compareObjects<T extends object, T2 extends object>( obj1: T, obj2: T2 ): boolean { // 如果两个对象引用相同,直接返回true if ((obj1 as object) === (obj2 as object)) { return true; } // 如果其中一个是null或不是对象,返回false if (!obj1 || !obj2 || typeof obj1 !== "object" || typeof obj2 !== "object") { return false; } // 如果一个是数组而另一个不是,返回false if (isArray(obj1) !== isArray(obj2)) { return false; } // 获取两个对象的所有属性名 const keys1 = Object.keys(obj1); const keys2 = Object.keys(obj2); // 如果属性数量不同,返回false if (keys1.length !== keys2.length) { return false; } // 遍历所有属性进行比较 for (const key of keys1) { const val1 = obj1[key as keyof T]; const val2 = obj2[key as keyof T2]; // 如果属性值是对象且不是函数,递归比较 if (isObject(val1) && isObject(val2)) { if (!compareObjects(val1, val2)) { return false; } } // 否则直接比较值(包括函数) else if ((val1 as unknown) !== (val2 as unknown)) { return false; } } return true; } export function isObject<T extends object>(value: unknown): value is T { return typeof value === "object" && value !== null; } export function cloneObject<T extends object>(data: T, deep?: boolean): T { function _clone<T extends object>(data: T, cache = new WeakMap<T, T>()): T { const _cache = cache.get(data); if (_cache) { return _cache; } const cloned = Object.create(Reflect.getPrototypeOf(data)) as T; cache.set(data, cloned); const keys = Reflect.ownKeys(data); for (let i = 0; i < keys.length; i++) { const desc = Reflect.getOwnPropertyDescriptor(data, keys[i]); if (!desc) { continue; } const clonedDesc = { ...desc }; if (Reflect.has(desc, "value")) { const value = Reflect.get(clonedDesc, "value", clonedDesc); Reflect.set( clonedDesc, "value", deep && isObject(value) ? _clone<object>(value, cache) : value, clonedDesc ); } Reflect.defineProperty(cloned, keys[i], clonedDesc); } return cloned; } return _clone(data); }