1. 精确获取小数位数
/*** 获取数字的小数位数(支持科学计数法)* @param {number|string} num - 要检查的数字,可以是数字或字符串形式* @returns {number} 返回小数部分的位数* * 实现原理:* 1. 处理科学计数法(如1.23e-5)* 2. 常规数字直接计算小数点后的位数* 3. 自动忽略末尾无意义的0(如12.340返回2位)* * 示例:* getDecimalPlaces(123.456) => 3* getDecimalPlaces(1.23e-5) => 7 (0.0000123)*/
function getDecimalPlaces(num) {// 转换为字符串并处理科学计数法const numStr = String(num).toLowerCase();// 处理科学计数法(如1.23e-5)if (numStr.includes('e')) {const [base, exponent] = numStr.split('e');const baseDecimal = base.split('.')[1]?.length || 0;// 计算实际小数位数 = 基数小数位数 - 指数绝对值return Math.max(0, baseDecimal - parseInt(exponent));}// 常规数字处理const decimalIndex = numStr.indexOf('.');// 没有小数点返回0,否则计算小数点后的字符数return decimalIndex === -1 ? 0 : numStr.length - decimalIndex - 1;
}
2. 深度对象比较(递归实现)
/*** 深度比较两个对象或值是否完全相等(递归实现)* @param {*} obj1 - 第一个比较对象* @param {*} obj2 - 第二个比较对象* @returns {boolean} 如果相等返回true,否则false* * 功能特点:* 1. 支持基本类型比较(number, string, boolean等)* 2. 支持数组比较(包括嵌套数组)* 3. 支持对象比较(包括嵌套对象)* 4. 处理了循环引用的情况* * 示例:* deepEqual({a:1,b:{c:2}}, {a:1,b:{c:2}}) => true*/
function deepEqual(obj1, obj2) {// 快速路径:如果是同一个对象或值相同if (obj1 === obj2) return true;// 处理null/undefined和基本类型if (obj1 == null || obj2 == null || typeof obj1 !== 'object' || typeof obj2 !== 'object') {return obj1 === obj2;}// 处理数组比较if (Array.isArray(obj1) && Array.isArray(obj2)) {// 数组长度不同直接返回falseif (obj1.length !== obj2.length) return false;// 递归比较每个元素for (let i = 0; i < obj1.length; i++) {if (!deepEqual(obj1[i], obj2[i])) return false;}return true;}// 获取两个对象的键const keys1 = Object.keys(obj1);const keys2 = Object.keys(obj2);// 键数量不同直接返回falseif (keys1.length !== keys2.length) return false;// 检查所有键值是否相等for (const key of keys1) {// 检查key是否存在和对应的值是否相等if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {return false;}}return true;
}
3. 安全的深拷贝实现
/*** 深拷贝对象或数组(解决JSON.parse(JSON.stringify())的局限)* @param {*} obj - 要拷贝的对象* @returns {*} 返回深拷贝后的新对象* * 与JSON方法的区别:* 1. 保留Date对象(而不是变成字符串)* 2. 保留RegExp对象(而不是变成空对象)* 3. 处理循环引用(本示例未实现,实际项目需要额外处理)* * 示例:* const obj = {a:1, b: {c:2}};* const copy = deepClone(obj);*/
function deepClone(obj) {// 处理基本类型和null/undefinedif (obj === null || typeof obj !== 'object') {return obj;}// 处理Date对象if (obj instanceof Date) {return new Date(obj.getTime()); // 复制时间戳}// 处理数组if (Array.isArray(obj)) {return obj.map(item => deepClone(item)); // 递归拷贝每个元素}// 处理普通对象const cloned = {};for (const key in obj) {// 只拷贝对象自身的属性(不拷贝原型链上的)if (obj.hasOwnProperty(key)) {cloned[key] = deepClone(obj[key]); // 递归拷贝每个属性}}return cloned;
}
4. 防抖与节流函数对比
/*** 防抖函数(延迟执行)* @param {Function} fn - 要执行的函数* @param {number} delay - 延迟时间(毫秒)* @returns {Function} 返回包装后的函数* * 应用场景:* 1. 搜索框输入(停止输入300ms后再搜索)* 2. 窗口resize事件(停止调整300ms后再计算布局)* * 原理:* 每次调用都清除之前的定时器,重新计时*/
function debounce(fn, delay = 300) {let timer = null;return function(...args) {clearTimeout(timer); // 清除之前的定时器timer = setTimeout(() => {fn.apply(this, args); // 延迟执行}, delay);};
}/*** 节流函数(固定间隔执行)* @param {Function} fn - 要执行的函数* @param {number} interval - 执行间隔(毫秒)* @returns {Function} 返回包装后的函数* * 应用场景:* 1. 滚动事件(每100ms检查一次位置)* 2. 鼠标移动事件(避免过于频繁的触发)* * 原理:* 记录上次执行时间,只有超过间隔才执行*/
function throttle(fn, interval = 300) {let lastTime = 0; // 上次执行时间return function(...args) {const now = Date.now();if (now - lastTime >= interval) { // 检查是否达到间隔fn.apply(this, args);lastTime = now; // 更新最后执行时间}};
}
5. 增强版类型检测
/*** 精确判断JavaScript数据类型* @param {*} value - 要检测的值* @returns {string} 返回类型字符串* * 支持的类型:* 'null', 'undefined', 'boolean', 'number', 'string', * 'symbol', 'function', 'array', 'date', 'regexp', * 'error', 'map', 'set', 'weakmap', 'weakset', 'promise', 'object'*/
function getType(value) {// 优先处理null和undefinedif (value === null) return 'null';if (value === undefined) return 'undefined';// 处理基本类型const type = typeof value;if (type !== 'object') return type;// 使用Object.prototype.toString获取精确类型const toString = Object.prototype.toString.call(value);// 类型映射表const typeMap = {'[object Array]': 'array','[object Date]': 'date','[object RegExp]': 'regexp','[object Error]': 'error','[object Map]': 'map','[object Set]': 'set','[object WeakMap]': 'weakmap','[object WeakSet]': 'weakset','[object Promise]': 'promise'};// 返回映射表中的类型或默认objectreturn typeMap[toString] || 'object';
}
6. 对象数组按属性去重
/*** 对象数组根据指定属性去重* @param {Array} arr - 对象数组* @param {string} key - 用作比较的属性名* @returns {Array} 返回去重后的新数组* * 实现原理:* 使用Set记录已经出现过的属性值* 只保留每个属性值第一次出现的对象* * 示例:* uniqueByKey([{id:1},{id:2},{id:1}], 'id') => [{id:1},{id:2}]*/
function uniqueByKey(arr, key) {const seen = new Set(); // 存储已出现的key值return arr.filter(item => {const val = item[key]; // 获取当前对象的key属性值if (seen.has(val)) {return false; // 如果已经存在则过滤掉}seen.add(val); // 记录新的key值return true; // 保留当前对象});
}
7. 高级数字格式化
/*** 数字格式化(千分位和小数位控制)* @param {number} num - 要格式化的数字* @param {number} decimals - 保留小数位数(默认2)* @returns {string} 格式化后的字符串* * 功能特点:* 1. 自动添加千分位逗号* 2. 精确控制小数位数* 3. 处理四舍五入* * 示例:* formatNumber(1234567.89123, 2) => "1,234,567.89"*/
function formatNumber(num, decimals = 2) {// 先转换为指定位数的小数字符串const numStr = num.toFixed(decimals);// 拆分整数和小数部分const [integer, decimal] = numStr.split('.');// 添加千分位逗号const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');// 如果有小数部分则拼接,否则只返回整数return decimal ? `${formattedInteger}.${decimal}` : formattedInteger;
}
8. 安全的JSON解析
/*** 安全的JSON解析(带错误处理)* @param {string} jsonStr - JSON字符串* @param {*} defaultValue - 解析失败时返回的默认值* @returns {*} 解析后的对象或默认值* * 为什么要用:* 1. JSON.parse在解析错误字符串时会抛出异常* 2. 这个封装确保始终返回有效结果* * 示例:* safeParse('{"a":1}') => {a:1}* safeParse('invalid', {}) => {}*/
function safeParse(jsonStr, defaultValue = null) {try {return JSON.parse(jsonStr);} catch (e) {console.error('JSON解析失败:', e);return defaultValue;}
}