/** * 节流函数 * @param func 要节流的函数 * @param wait 等待时间(毫秒) * @param options 选项 */ export function throttle unknown>( func: T, wait: number, options: { leading?: boolean; trailing?: boolean } = {} ): (...args: Parameters) => void { let timeout: ReturnType | null = null; let previous = 0; const { leading = true, trailing = true } = options; return function(this: unknown, ...args: Parameters) { const now = Date.now(); if (!previous && !leading) previous = now; const remaining = wait - (now - previous); if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; func.apply(this, args); } else if (!timeout && trailing) { timeout = setTimeout(() => { previous = leading ? Date.now() : 0; timeout = null; func.apply(this, args); }, remaining); } }; } /** * 深拷贝函数 * @param obj 要拷贝的对象 * @returns 深拷贝后的对象 */ export const deepClone = (obj: T): T => { if (obj === null || typeof obj !== 'object') { return obj; } // 处理日期对象 if (obj instanceof Date) { return new Date(obj.getTime()) as unknown as T; } // 处理数组 if (Array.isArray(obj)) { return obj.map(item => deepClone(item)) as unknown as T; } // 处理普通对象 const clonedObj = {} as T; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; }; /** * 深度比较两个值是否相等 * @param a 第一个值 * @param b 第二个值 * @returns 是否相等 */ export function deepEqual(a: unknown, b: unknown): boolean { if (a === b) return true; if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) { return false; } const keysA = Object.keys(a as Record); const keysB = Object.keys(b as Record); if (keysA.length !== keysB.length) return false; for (const key of keysA) { if (!keysB.includes(key) || !deepEqual((a as Record)[key], (b as Record)[key])) { return false; } } return true; } /** * 从对象中选取指定的属性 * @param obj 源对象 * @param keys 要选取的属性键数组 * @returns 包含指定属性的新对象 */ export function pick, K extends keyof T>( obj: T, keys: K[] ): Pick { const result = {} as Pick; for (const key of keys) { if (key in obj) { result[key] = obj[key]; } } return result; } /** * 从对象中排除指定的属性 * @param obj 源对象 * @param keys 要排除的属性键数组 * @returns 排除指定属性后的新对象 */ export function omit, K extends keyof T>( obj: T, keys: K[] ): Omit { const result = { ...obj } as T; for (const key of keys) { delete result[key]; } return result as Omit; } /** * 合并多个对象 * @param objects 要合并的对象数组 * @returns 合并后的新对象 */ export function merge>(...objects: Partial[]): T { const result = {} as T; for (const obj of objects) { if (obj && typeof obj === 'object') { Object.assign(result, obj); } } return result; } /** * 将对象转换为查询字符串 * @param obj 要转换的对象 * @returns 查询字符串 */ export const toQueryString = (obj: Record): string => { const params = new URLSearchParams(); for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { const value = obj[key]; if (value !== null && value !== undefined) { params.append(key, String(value)); } } } return params.toString(); }; /** * 将查询字符串转换为对象 * @param queryString 查询字符串 * @returns 转换后的对象 */ export const fromQueryString = (queryString: string): Record => { const params = new URLSearchParams(queryString); const result: Record = {}; for (const [key, value] of params.entries()) { result[key] = value; } return result; }; /** * 数组去重 * @param array 要去重的数组 * @param keyFn 可选的键函数,用于复杂对象去重 * @returns 去重后的数组 */ export const unique = ( array: T[], keyFn?: (item: T) => K ): T[] => { if (!keyFn) { return [...new Set(array)]; } const seen = new Set(); return array.filter(item => { const key = keyFn(item); if (seen.has(key)) { return false; } seen.add(key); return true; }); }; /** * 数组分组 * @param array 要分组的数组 * @param keyFn 分组键函数 * @returns 分组后的对象 */ export const groupBy = ( array: T[], keyFn: (item: T) => K ): Record => { return array.reduce((groups, item) => { const key = keyFn(item); if (!groups[key]) { groups[key] = []; } groups[key].push(item); return groups; }, {} as Record); }; /** * 数组排序 * @param array 要排序的数组 * @param compareFn 比较函数 * @returns 排序后的新数组 */ export const sortBy = ( array: T[], compareFn?: (a: T, b: T) => number ): T[] => { return [...array].sort(compareFn); }; /** * 防抖函数 * @param func 要防抖的函数 * @param wait 等待时间(毫秒) * @param immediate 是否立即执行 */ export function debounce unknown>( func: T, wait: number, immediate = false ): (...args: Parameters) => void { let timeout: ReturnType | null = null; return function(this: unknown, ...args: Parameters) { const later = () => { timeout = null; if (!immediate) func.apply(this, args); }; const callNow = immediate && !timeout; if (timeout) clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(this, args); }; }