JavaScript 常用工具函数
防抖 (Debounce)
触发事件后延迟 n 秒执行函数,若 n 秒内再次触发则重新计时(适用于输入框搜索、窗口 resize 等频繁触发的场景)。
javascript
/**
* 防抖函数
* @param {Function} func - 需要防抖的函数
* @param {number} delay - 延迟时间(毫秒)
* @param {boolean} immediate - 是否立即执行(首次触发时立即执行,之后防抖)
* @returns {Function} 防抖处理后的函数
*/
function debounce(func, delay = 300, immediate = false) {
let timer = null;
return function (...args) {
// 清除之前的定时器
if (timer) clearTimeout(timer);
// 立即执行模式:首次触发且无定时器时直接执行
if (immediate && !timer) {
func.apply(this, args);
}
// 重置定时器
timer = setTimeout(() => {
// 非立即执行模式:延迟后执行
if (!immediate) {
func.apply(this, args);
}
timer = null; // 执行后清空定时器
}, delay);
};
}
// 使用示例:输入框搜索防抖
const input = document.querySelector('input');
input.oninput = debounce((e) => {
console.log('搜索:', e.target.value);
}, 500);
typescript
/**
* 防抖函数
* @param {Function} func - 需要防抖的函数
* @param {number} delay - 延迟时间(毫秒)
* @param {boolean} immediate - 是否立即执行(首次触发时立即执行,之后防抖)
* @returns {Function} 防抖处理后的函数
*/
function debounce<T extends (...args: any[]) => any>(
func: T,
delay: number = 300,
immediate: boolean = false
): (...args: Parameters<T>) => void {
let timer: NodeJS.Timeout | null = null;
return function (...args: Parameters<T>): void {
if (timer) clearTimeout(timer);
if (immediate && !timer) {
func.apply(this, args);
}
timer = setTimeout(() => {
if (!immediate) {
func.apply(this, args);
}
timer = null;
}, delay);
};
}
// 使用示例
const input = document.querySelector('input');
if (input) {
input.oninput = debounce((e: Event) => {
console.log('搜索:', (e.target as HTMLInputElement).value);
}, 500);
}
节流 (Throttle)
每隔 n 秒最多执行一次函数(适用于滚动加载、高频点击等需要限制执行频率的场景)。
javascript
/**
* 节流函数(时间戳版)
* @param {Function} func - 需要节流的函数
* @param {number} interval - 间隔时间(毫秒)
* @returns {Function} 节流处理后的函数
*/
function throttle(func, interval = 300) {
let lastTime = 0; // 上次执行时间
return function (...args) {
const now = Date.now();
// 若当前时间 - 上次执行时间 >= 间隔,则执行
if (now - lastTime >= interval) {
func.apply(this, args);
lastTime = now; // 更新上次执行时间
}
};
}
// 使用示例:滚动监听节流
window.onscroll = throttle(() => {
console.log('滚动位置:', window.scrollY);
}, 1000);
typescript
/**
* 节流函数(时间戳版)
* @param {Function} func - 需要节流的函数
* @param {number} interval - 间隔时间(毫秒)
* @returns {Function} 节流处理后的函数
*/
function throttle<T extends (...args: any[]) => any>(
func: T,
interval: number = 300
): (...args: Parameters<T>) => void {
let lastTime = 0;
return function (...args: Parameters<T>): void {
const now = Date.now();
if (now - lastTime >= interval) {
func.apply(this, args);
lastTime = now;
}
};
}
// 使用示例
window.onscroll = throttle(() => {
console.log('滚动位置:', window.scrollY);
}, 1000);
深克隆 (Deep Clone)
完全复制一个对象(包括嵌套对象、数组等),避免原对象被修改时影响克隆对象(解决浅拷贝的引用问题)。
javascript
/**
* 深克隆函数(支持对象、数组、日期、正则等)
* @param {*} target - 需要克隆的值
* @returns {*} 克隆后的新值
*/
function deepClone(target) {
// 基本类型直接返回(null 特殊处理)
if (target === null || typeof target !== 'object') {
return target;
}
let cloneResult;
// 处理日期
if (target instanceof Date) {
cloneResult = new Date();
cloneResult.setTime(target.getTime());
return cloneResult;
}
// 处理正则
if (target instanceof RegExp) {
cloneResult = new RegExp(target.source, target.flags);
return cloneResult;
}
// 处理数组或对象(根据原类型创建新容器)
cloneResult = Array.isArray(target) ? [] : {};
// 递归克隆属性
for (const key in target) {
if (target.hasOwnProperty(key)) { // 只克隆自身属性(排除原型链)
cloneResult[key] = deepClone(target[key]);
}
}
return cloneResult;
}
// 使用示例
const obj = {a: 1, b: {c: 2}, d: [3, 4]};
const cloneObj = deepClone(obj);
cloneObj.b.c = 100;
console.log(obj.b.c); // 2(原对象不受影响)
typescript
/**
* 深克隆函数(支持对象、数组、日期、正则等)
* @param {T} target - 需要克隆的值
* @returns {T} 克隆后的新值
*/
function deepClone<T>(target: T): T {
// 基本类型直接返回
if (target === null || typeof target !== 'object') {
return target;
}
let cloneResult: any;
// 处理日期
if (target instanceof Date) {
cloneResult = new Date();
cloneResult.setTime(target.getTime());
return cloneResult as T;
}
// 处理正则
if (target instanceof RegExp) {
cloneResult = new RegExp(target.source, target.flags);
return cloneResult as T;
}
// 处理数组或对象
if (Array.isArray(target)) {
cloneResult = [] as T extends Array<any> ? T : never;
} else {
cloneResult = {} as T;
}
// 递归克隆属性
for (const key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
cloneResult[key] = deepClone(target[key]);
}
}
return cloneResult;
}
// 使用示例
const obj = {a: 1, b: {c: 2}, d: [3, 4]};
const cloneObj = deepClone(obj);
cloneObj.b.c = 100;
console.log(obj.b.c); // 2(原对象不受影响)
检测数据类型 (Check Type)
精确判断变量的类型(比 typeof 更准确,如区分数组、对象、null 等)。
javascript
/**
* 检测数据类型
* @param {*} value - 需要检测的值
* @returns {string} 类型字符串(如 'array'、'object'、'null' 等)
*/
function checkType(value) {
// 利用 Object.prototype.toString 精确获取类型
const typeStr = Object.prototype.toString.call(value);
// 提取类型(如 "[object Array]" → "array")
return typeStr.slice(8, -1).toLowerCase();
}
// 使用示例
console.log(checkType([])); // 'array'
console.log(checkType({})); // 'object'
console.log(checkType(null)); // 'null'
console.log(checkType(123)); // 'number'
console.log(checkType(async () => {
})); // 'asyncfunction'
typescript
/**
* 检测数据类型
* @param {unknown} value - 需要检测的值
* @returns {string} 类型字符串(如 'array'、'object'、'null' 等)
*/
function checkType(value: unknown): string {
const typeStr = Object.prototype.toString.call(value);
return typeStr.slice(8, -1).toLowerCase();
}
// 使用示例
console.log(checkType([])); // 'array'
console.log(checkType({})); // 'object'
console.log(checkType(null)); // 'null'
console.log(checkType(123)); // 'number'
console.log(checkType(async () => {
})); // 'asyncfunction'
格式化日期 (Format Date)
将时间戳或 Date 对象格式化为指定字符串(如 YYYY-MM-DD HH:MM:SS)。
javascript
/**
* 格式化日期
* @param {Date|number} date - 日期(Date对象或时间戳)
* @param {string} format - 格式字符串(YYYY-MM-DD HH:MM:SS)
* @returns {string} 格式化后的日期字符串
*/
function formatDate(date, format = 'YYYY-MM-DD HH:MM:SS') {
if (typeof date === 'number') {
date = new Date(date); // 时间戳转 Date 对象
}
if (!(date instanceof Date) || isNaN(date.getTime())) {
throw new Error('无效的日期');
}
const o = {
'Y+': date.getFullYear(), // 年
'M+': date.getMonth() + 1, // 月(0-11,需+1)
'D+': date.getDate(), // 日
'H+': date.getHours(), // 时
'm+': date.getMinutes(), // 分
's+': date.getSeconds() // 秒
};
// 替换格式中的年、月、日等(补零处理)
for (const k in o) {
const reg = new RegExp(`(${k})`);
if (reg.test(format)) {
const value = o[k].toString();
// 若格式为 YY,则取年份后两位;否则补零至对应长度(如 M 转 09)
format = format.replace(reg,
RegExp.$1.length === 1 ? value : value.padStart(RegExp.$1.length, '0')
);
}
}
return format;
}
// 使用示例
console.log(formatDate(new Date())); // 2025-10-17 15:30:45
console.log(formatDate(1753000000000, 'MM/DD/YYYY')); // 06/18/2025
typescript
type DateFormat = 'YYYY-MM-DD' | 'YYYY-MM-DD HH:MM:SS' | 'MM/DD/YYYY' | string;
/**
* 格式化日期
* @param {Date|number} date - 日期(Date对象或时间戳)
* @param {DateFormat} format - 格式字符串(YYYY-MM-DD HH:MM:SS)
* @returns {string} 格式化后的日期字符串
*/
function formatDate(
date: Date | number,
format: DateFormat = 'YYYY-MM-DD HH:MM:SS'
): string {
if (typeof date === 'number') {
date = new Date(date);
}
if (!(date instanceof Date) || isNaN(date.getTime())) {
throw new Error('无效的日期');
}
const o: Record<string, number> = {
'Y+': date.getFullYear(),
'M+': date.getMonth() + 1,
'D+': date.getDate(),
'H+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
};
for (const k in o) {
const reg = new RegExp(`(${k})`);
if (reg.test(format)) {
const value = o[k].toString();
format = format.replace(
reg,
RegExp.$1.length === 1 ? value : value.padStart(RegExp.$1.length, '0')
);
}
}
return format;
}
// 使用示例
console.log(formatDate(new Date())); // 2025-10-17 15:30:45
console.log(formatDate(1753000000000, 'MM/DD/YYYY')); // 06/18/2025