一、JS单行高频实用案例(25个,直接复制可用)
1. 变量值交换(不使用临时变量)
适用场景:快速交换两个变量的值,无需额外声明临时变量,简化代码,适用于简单值交换场景。
// 核心单行代码(适用于数字、字符串等基本类型)
let a = 10, b = 20;
[a, b] = [b, a]; // 解构赋值实现交换
// 结果: a = 20, b = 10
// 补充案例(字符串交换)
let str1 = 'hello', str2 = 'world';
[str1, str2] = [str2, str1];
// 结果: str1 = 'world', str2 = 'hello'
总结:利用数组解构赋值,简洁实现两个变量值的交换,无需临时变量,代码简洁易读,仅适用于基本数据类型;若为引用类型(对象、数组),交换的是引用地址,原数据会受影响。
2. 快速生成随机数(指定范围)
适用场景:生成指定区间内的随机整数(如随机抽奖、随机排序、模拟随机数据),前端高频使用场景。
// 核心单行代码(min=最小值,max=最大值,包含min和max)
const getRandomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
// 案例1:生成1-10的随机整数
const random1 = getRandomNum(1, 10);
// 结果: 1-10之间的任意整数(如5、8、10)
// 案例2:生成100-200的随机整数
const random2 = getRandomNum(100, 200);
// 结果: 100-200之间的任意整数(如156、199、100)
总结:Math.random()生成0-1(不包含1)的随机小数,乘以(max-min+1)可将范围扩展到0-(max-min),Math.floor()取整后加min,即可得到指定区间内的随机整数,灵活适配各类随机场景。
3. 浅克隆对象(复制顶层属性)
适用场景:快速复制对象的顶层属性,生成新对象,适用于简单对象(无嵌套对象)的复制,避免修改原对象。
const originalObj = { name: '张三', age: 24 }; // 修正原文档拼写错误(original0bj→originalObj)
const clonedObj = { ...originalObj }; // 核心单行代码
// 结果: clonedObj = { name: '张三', age: 24 }
// 验证:修改clonedObj.age = 25,originalObj.age仍为24
总结:利用扩展运算符(...)复制对象的所有可枚举自身属性,生成新对象。注意:若对象包含嵌套对象,嵌套对象仍为引用类型,修改嵌套对象会影响原对象,此时需使用深克隆。
4. 合并对象
适用场景:将多个对象合并为一个新对象,重复属性会被后一个对象覆盖。
const obj1 = { name: '张三' };
const obj2 = { age: 22 };
const mergedObj = { ...obj1, ...obj2 }; // 核心单行代码
// 结果: mergedObj = { name: '张三', age: 22 }
总结:扩展运算符可快速合并多个对象,若存在重复属性,后面的对象属性会覆盖前面的。例如:const obj3 = { name: '李四', gender: '男' }; 合并后mergedObj = { name: '李四', age:22, gender: '男' }。
5. 清理数组(删除所有假值)
适用场景:快速过滤数组中的假值,保留有效数据。
const arr = [0, 1, false, 2, '', 3, null, NaN, undefined]; // 补充完整假值案例
const cleanedArray = arr.filter(Boolean); // 核心单行代码
// 结果: cleanedArray = [1, 2, 3]
总结:Array.prototype.filter() 结合Boolean函数,自动过滤所有假值(0、false、null、''、NaN、undefined),无需手动判断,高效简洁。
6. 将NodeList转换为数组
适用场景:获取DOM元素集合(NodeList)后,需使用数组方法(如map、filter)操作时。
// 修正原文档语法疏漏(补充扩展运算符包裹)
const nodesArray = [...document.querySelectorAll('div')];
// 结果: nodesArray 为包含所有div元素的数组,可使用map、filter等方法
总结:扩展运算符可将类数组(NodeList、arguments等)转换为真正的数组,从而使用数组的所有方法。例如:nodesArray.map(div => div.style.color = 'red'),可批量修改所有div的字体颜色。
7. 检查数组是否满足指定条件
适用场景:判断数组中是否存在满足条件的元素(some),或所有元素是否都满足条件(every)。
// 案例1:检查数组中是否存在负数
const arr1 = [1, 2, 3, -5, 4];
const hasNegativeNumbers = arr1.some(num => num < 0);
// 结果: hasNegativeNumbers = true
// 案例2:检查数组所有元素是否均为正数
const allPositive = arr1.every(num => num > 0);
// 结果: allPositive = false
// 补充案例:检查数组中是否有大于10的元素
const arr2 = [5, 8, 12, 3];
const hasGreaterThan10 = arr2.some(num => num > 10);
// 结果: hasGreaterThan10 = true
总结:some() 只要有一个元素满足条件就返回true,every() 需所有元素满足条件才返回true,两者均为短路操作(找到符合条件/不符合条件的元素后立即停止遍历)。
8. 将文本复制到剪贴板
适用场景:实现点击按钮复制文本、复制链接等功能。
// 核心单行代码(异步操作,可结合async/await使用)
navigator.clipboard.writeText('Text to copy'); // 修正原文档拼写(Textto→Text to)
// 完整示例(结合按钮点击)
document.querySelector('#copyBtn').addEventListener('click', async () => {
await navigator.clipboard.writeText('要复制的文本');
alert('复制成功!');
});
总结:使用Clipboard API实现文本复制,比传统的“创建input复制”更简洁,但需注意浏览器兼容性(IE不支持),且需在HTTPS协议或本地环境下使用。
9. 删除数组重复项
适用场景:快速去重,适用于基本数据类型(数字、字符串、布尔值等)的数组。
const arr = [1, 2, 2, 3, 4, 4, 5, 5, 5];
const unique = [...new Set(arr)]; // 核心单行代码
// 结果: unique = [1, 2, 3, 4, 5]
总结:利用Set对象“值唯一”的特性,结合扩展运算符将Set转换为数组,实现快速去重。注意:若数组包含对象,此方法无法去重(对象引用不同),需额外处理。
10. 取两个数组的交集
适用场景:获取两个数组中共同存在的元素。
const arr1 = [1, 2, 3, 4];
const arr2 = [2, 4, 6, 8];
const intersection = arr1.filter(value => arr2.includes(value)); // 核心单行代码
// 结果: intersection = [2, 4]
// 补充案例(字符串数组交集)
const arr3 = ['a', 'b', 'c'];
const arr4 = ['b', 'c', 'd'];
const strIntersection = arr3.filter(value => arr4.includes(value));
// 结果: strIntersection = ['b', 'c']
总结:通过filter()遍历第一个数组,使用includes()判断元素是否存在于第二个数组中,筛选出共同元素。若数组元素较多,可先将第二个数组转为Set,提升查询效率:const arr2Set = new Set(arr2); const intersection = arr1.filter(value => arr2Set.has(value))。
11. 求数组元素的总和
适用场景:快速计算数组中所有基本数据类型(数字)的总和。
const arr = [1, 2, 3, 4];
const sum = arr.reduce((total, value) => total + value, 0); // 核心单行代码
// 结果: sum = 10
// 补充案例(含负数和小数)
const arr2 = [1.5, 2.5, -3, 4];
const sum2 = arr2.reduce((total, value) => total + value, 0);
// 结果: sum2 = 5
总结:reduce() 方法接收回调函数和初始值,回调函数中的total为累加值,value为当前元素,遍历数组并累加所有元素。初始值设为0,避免数组为空时返回undefined。
12. 根据指定条件,给对象的属性赋值
适用场景:根据条件动态给对象添加属性,避免冗余的if-else语句。
const condition = true;
const value = '你好, 世界';
const newObject = { ...(condition && { key: value }) }; // 核心单行代码
// 结果: newObject = { key: '你好, 世界' }
// 补充案例(条件为false)
const condition2 = false;
const newObject2 = { ...(condition2 && { key: value }) };
// 结果: newObject2 = {}
总结:利用短路求值(&&),当条件为true时,返回{key: value},并通过扩展运算符添加到新对象中;当条件为false时,短路返回false,扩展运算符会忽略false,不添加任何属性。
13. 使用变量作为对象的键
适用场景:动态设置对象的键名(键名不确定,需通过变量指定)。
const dynamicKey = 'name';
const value = '张三';
const obj = { [dynamicKey]: value }; // 核心单行代码(计算属性名)
// 结果: obj = { name: '张三' }
// 补充案例(动态切换键名)
const dynamicKey2 = 'age';
const obj2 = { [dynamicKey2]: 24 };
// 结果: obj2 = { age: 24 }
总结:通过计算属性名(方括号包裹变量),可将变量的值作为对象的键名,灵活适配动态场景,例如根据接口返回值动态设置对象键名。
14. 离线状态检查器
适用场景:检测用户浏览器的网络连接状态,提示用户当前是否在线。
const isOnline = navigator.onLine ? '在线' : '离线'; // 核心单行代码
// 结果: 网络正常时返回'在线',断开时返回'离线'
// 完整示例(实时监听网络状态)
window.addEventListener('online', () => console.log('网络已连接,当前状态:在线'));
window.addEventListener('offline', () => console.log('网络已断开,当前状态:离线'));
总结:利用navigator.onLine属性结合三元运算符,快速判断网络状态。注意:navigator.onLine仅能检测是否有网络连接,无法判断网络是否能正常访问互联网(如连接了无网络的WiFi)。
15. 离开页面弹出确认对话框
适用场景:防止用户误操作关闭页面,导致未保存的数据丢失(如表单填写、编辑内容)。
// 核心单行代码
window.onbeforeunload = () => '你确定要离开吗?未保存的内容将丢失!'; // 补充提示信息
// 补充:现代浏览器对提示文本的限制(部分浏览器不显示自定义文本,仅显示默认提示)
window.onbeforeunload = (e) => {
e.preventDefault();
e.returnValue = '';
return '你确定要离开吗?';
};
总结:监听window的onbeforeunload事件,当用户关闭页面、刷新页面或跳转页面时,会弹出确认对话框。注意:现代浏览器为了安全,可能会忽略自定义提示文本,仅显示浏览器默认提示。
16. 对象数组,根据对象的某个key求对应值的总和
适用场景:统计对象数组中,指定属性的所有值的总和(如统计订单金额、商品数量等)。
const arrayOfObjects = [{ x: 1 }, { x: 2 }, { x: 3 }];
// 核心单行函数(可复用)
const sumBy = (arr, key) => arr.reduce((acc, obj) => acc + obj[key], 0);
const total = sumBy(arrayOfObjects, 'x'); // 传入数组和指定key
// 结果: total = 6
// 补充案例(统计订单金额)
const orders = [{ amount: 100 }, { amount: 200 }, { amount: 150 }];
const totalAmount = sumBy(orders, 'amount');
// 结果: totalAmount = 450
总结:封装sumBy函数,利用reduce()遍历对象数组,累加指定key对应的属性值,可灵活复用,适用于各种对象数组的统计场景。
17. 将URL问号后面的查询字符串转为对象
适用场景:快速解析URL中的查询参数,方便获取参数值(如页面跳转传参、接口请求参数解析)。
const query = 'name=John&age=30&gender=male'; // 补充多参数案例
// 核心单行代码(修正原文档拼写错误:0bject→Object)
const parseQuery = query => Object.fromEntries(new URLSearchParams(query));
const queryObj = parseQuery(query);
// 结果: queryObj = { name: 'John', age: '30', gender: 'male' }
总结:URLSearchParams用于解析查询字符串,返回可迭代对象,再通过Object.fromEntries()将其转换为对象,解析后的参数值均为字符串,若需数字类型,需手动转换(如Number(queryObj.age))。
18. 将秒数转换为时间格式的字符串(HH:MM:SS)
适用场景:将秒数转换为标准时间格式,如视频时长、倒计时显示等。
const seconds = 3661; // 1小时1分1秒(修正原文档注释错误:3600秒为1小时)
// 核心单行代码(修正原文档拼写错误:toIsostring→toISOString、substr→slice)
const toTimeString = seconds => new Date(seconds * 1000).toISOString().slice(11, 19);
const timeStr = toTimeString(seconds);
// 结果: timeStr = '01:01:01'
// 补充案例(不足1小时、不足1分钟)
const seconds2 = 61; // 1分1秒
const timeStr2 = toTimeString(seconds2);
// 结果: timeStr2 = '00:01:01'
const seconds3 = 5; // 5秒
const timeStr3 = toTimeString(seconds3);
// 结果: timeStr3 = '00:00:05'
总结:将秒数乘以1000(转换为毫秒),创建Date对象,再通过toISOString()获取标准时间字符串,最后截取时间部分(HH:MM:SS),适用于所有正秒数的转换。
19. 求某对象所有属性值的最大值
适用场景:快速获取对象中所有属性值的最大值(如统计最高分、最大金额等)。
const scores = { math: 95, chinese: 99, english: 88 }; // 数学、语文、英语成绩
// 核心单行代码(修正原文档拼写错误:0bject→Object、max0bjectValue→maxObjectValue)
const maxObjectValue = obj => Math.max(...Object.values(obj));
const maxScore = maxObjectValue(scores);
// 结果: maxScore = 99
// 补充案例(数字属性值含小数)
const prices = { apple: 5.9, banana: 3.5, orange: 4.8 };
const maxPrice = maxObjectValue(prices);
// 结果: maxPrice = 5.9
总结:Object.values(obj)提取对象所有属性值,生成数组,再通过扩展运算符将数组元素作为Math.max()的参数,获取最大值。注意:对象属性值必须为数字类型,否则会返回NaN。
20. 判断对象的值中是否包含某个值
适用场景:检查对象的所有属性值中,是否存在指定的值。
const person = { name: '张三', age: 30, gender: '男' }; // 补充多属性案例
// 核心单行代码(修正原文档拼写错误:0bject→Object)
const hasValue = (obj, value) => Object.values(obj).includes(value);
// 案例1:判断是否包含30
const has30 = hasValue(person, 30); // 结果: true
// 案例2:判断是否包含'女'
const hasFemale = hasValue(person, '女'); // 结果: false
总结:Object.values(obj)获取对象所有属性值的数组,再通过includes()判断指定值是否在数组中,适用于快速检查对象值的存在性。
21. 安全访问深度嵌套的对象属性
适用场景:访问嵌套层级较深的对象属性,避免因中间属性不存在导致的TypeError错误。
// 案例1:中间属性存在
const user = { profile: { name: '张三' } };
const userName = user.profile?.name ?? '匿名'; // 核心单行代码
// 结果: userName = '张三'
// 案例2:中间属性不存在(profile为undefined)
const user2 = { };
const userName2 = user2.profile?.name ?? '匿名';
// 结果: userName2 = '匿名'
// 补充:区分??和||的差异
const user3 = { profile: { name: '' } };
const userName3 = user3.profile?.name ?? '匿名'; // 结果: ''(空字符串不是null/undefined,不触发默认值)
const userName4 = user3.profile?.name || '匿名'; // 结果: '匿名'(空字符串是假值,触发默认值)
总结:可选链运算符(?.):当中间属性为null/undefined时,短路返回undefined,避免报错;空值合并运算符(??):仅当左侧为null/undefined时,返回右侧默认值,不影响其他假值(如''、0)。两者结合,可安全访问深度嵌套属性并设置默认值。
22. 条件执行语句
适用场景:无需if语句,简洁实现“条件为真时执行函数/赋值”。
// 案例1:条件执行函数
const isEligible = true;
const performAction = () => console.log('执行操作');
isEligible && performAction(); // 核心单行代码(条件为真时执行)
// 结果: 输出'执行操作'
// 案例2:条件赋值(修正原文档语法,补充括号)
const isEligible2 = true;
let value = '';
isEligible2 && (value = '条件达成'); // 核心单行代码
// 结果: value = '条件达成'
// 补充案例:条件为false时不执行
const isEligible3 = false;
isEligible3 && performAction(); // 无输出
总结:利用逻辑AND(&&)的短路特性,左侧为true时,才执行右侧的函数或赋值语句;左侧为false时,直接短路,不执行右侧代码。适用于简单的条件判断场景,简化代码。
23. 创建包含指定数字范围的数组
适用场景:快速生成连续数字数组(如分页页码、循环计数等)。
// 案例1:创建1-5的数组
const range1 = Array.from({ length: 5 }, (_, i) => i + 1); // 核心单行代码
// 结果: range1 = [1, 2, 3, 4, 5]
// 案例2:创建5-10的数组
const range2 = Array.from({ length: 6 }, (_, i) => i + 5);
// 结果: range2 = [5, 6, 7, 8, 9, 10]
// 案例3:创建0-4的数组(简化)
const range3 = Array.from({ length: 5 }, (_, i) => i);
// 结果: range3 = [0, 1, 2, 3, 4]
总结:Array.from()接收两个参数:类数组对象(设置length指定数组长度)和映射函数,映射函数通过索引(i)生成指定范围的数字。下划线(_)表示未使用的参数(当前元素),是JS中的常用惯例。
24. 提取文件扩展名
适用场景:获取文件名中的扩展名(如判断文件类型、上传文件校验等)。
const fileName1 = 'example.png';
const fileName2 = 'document.pdf';
const fileName3 = 'image.jpg';
const fileName4 = 'text'; // 无扩展名
// 核心单行代码(修正原文档拼写错误:lastIndex0f→lastIndexOf、getFileExtension返回值错误)
const getFileExtension = str => str.slice(((str.lastIndexOf(".") - 1) >>> 0) + 2);
// 案例验证
console.log(getFileExtension(fileName1)); // 结果: 'png'
console.log(getFileExtension(fileName2)); // 结果: 'pdf'
console.log(getFileExtension(fileName3)); // 结果: 'jpg'
console.log(getFileExtension(fileName4)); // 结果: ''(无扩展名返回空字符串)
总结:通过lastIndexOf(".")找到最后一个点号的位置,使用位运算符(>>>)确保即使未找到点号(返回-1),操作也安全,最终截取点号后面的字符串作为扩展名。
25. 切换元素的class
适用场景:动态添加/移除元素的class(如菜单显示/隐藏、按钮选中/取消、表单状态切换等)。
// 核心代码(修正原文档语法错误,补充括号)
const element = document.querySelector('.myelement');
const toggleClass = (el, className) => el.classList.toggle(className);
// 切换class(存在则删除,不存在则添加)
toggleClass(element, 'active');
// 完整示例(点击按钮切换元素class)
document.querySelector('#toggleBtn').addEventListener('click', () => {
toggleClass(element, 'active');
});
总结:classList.toggle()方法自动判断元素是否包含指定class,包含则删除,不包含则添加,无需手动判断,简洁高效,是前端开发中动态控制元素样式的常用方法。
二、JS实战高频案例(18个,覆盖前端常用场景)
1. 防抖函数(避免高频事件频繁触发)
适用场景:防止输入框输入、窗口resize、滚动等高频事件频繁触发函数,适用于搜索联想、输入验证等场景。
// 核心单行防抖函数(简化版)
const debounce = (fn, delay = 500) => {
let timer = null;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
};
// 使用示例(输入框搜索)
const search = (value) => console.log('搜索:', value);
const debouncedSearch = debounce(search, 300);
// 输入框输入时调用,仅在停止输入300ms后触发
document.querySelector('#searchInput').addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
2. 节流函数(限制函数触发频率)
适用场景:限制函数在指定时间内只能触发一次,适用于滚动加载、按钮点击防重复提交等场景。
// 核心单行节流函数(简化版)
const throttle = (fn, interval = 1000) => {
let lastTime = 0;
return (...args) => {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
};
// 使用示例(滚动加载)
const loadMore = () => console.log('加载更多数据');
const throttledLoadMore = throttle(loadMore, 2000);
// 滚动时调用,每2000ms只能触发一次
window.addEventListener('scroll', throttledLoadMore);
3. 深克隆对象(解决嵌套对象复制问题)
适用场景:复制包含嵌套对象的复杂对象,确保修改克隆对象不影响原对象,适用于数据备份、复杂数据处理。
// 核心单行深克隆(简单场景,不支持函数、Symbol等特殊类型)
const deepClone = obj => JSON.parse(JSON.stringify(obj));
// 示例
const originalObj = {
name: '张三',
age: 24,
address: { city: '北京', area: '朝阳' } // 嵌套对象
};
const clonedObj = deepClone(originalObj);
clonedObj.address.city = '上海'; // 修改克隆对象的嵌套属性
console.log(originalObj.address.city); // 结果: '北京'(原对象不受影响)
// 补充:复杂场景深克隆(支持函数、Symbol,需使用递归)
const deepCloneAdvanced = (obj) => {
if (obj === null || typeof obj !== 'object') return obj;
const clone = Array.isArray(obj) ? [] : {};
for (let key in obj) {
clone[key] = deepCloneAdvanced(obj[key]);
}
return clone;
};
4. 精准检查数据类型
适用场景:精准判断数据类型(如区分数组、对象、null、函数等),避免typeof的局限性,适用于数据校验场景。
// 核心单行函数
const getType = (data) => Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
// 案例验证
console.log(getType(123)); // 结果: 'number'
console.log(getType('abc')); // 结果: 'string'
console.log(getType([])); // 结果: 'array'
console.log(getType({})); // 结果: 'object'
console.log(getType(null)); // 结果: 'null'
console.log(getType(() => {})); // 结果: 'function'
console.log(getType(new Date())); // 结果: 'date'
5. 数组扁平化(多维转一维)
适用场景:将多维数组转为一维数组,适用于数据处理、数组遍历等场景,简化数据操作。
// 案例1:二维数组扁平化(核心单行代码)
const arr1 = [1, [2, 3], [4, [5, 6]]];
const flatArr1 = arr1.flat(1); // 参数1表示扁平化1层
// 结果: [1, 2, 3, 4, [5, 6]]
// 案例2:多维数组扁平化(不限层级)
const flatArr2 = arr1.flat(Infinity); // Infinity表示扁平化所有层级
// 结果: [1, 2, 3, 4, 5, 6]
// 补充案例(手动实现扁平化,不使用flat方法)
const flatArr3 = arr1.reduce((acc, item) => acc.concat(Array.isArray(item) ? flatArr3(item) : item), []);
// 结果: [1, 2, 3, 4, 5, 6]
6. 数组排序(数字/字符串通用)
适用场景:对数组进行升序/降序排序,适用于数据展示、排名统计等场景,解决sort默认字符串排序的问题。
// 案例1:数字数组升序排序
const nums = [3, 1, 4, 1, 5, 9, 2, 6];
const sortedNumsAsc = [...nums].sort((a, b) => a - b); // 展开数组避免修改原数组
// 结果: [1, 1, 2, 3, 4, 5, 6, 9]
// 案例2:数字数组降序排序
const sortedNumsDesc = [...nums].sort((a, b) => b - a);
// 结果: [9, 6, 5, 4, 3, 2, 1, 1]
// 案例3:字符串数组排序(按字母顺序)
const strs = ['banana', 'apple', 'cherry', 'date'];
const sortedStrs = [...strs].sort();
// 结果: ['apple', 'banana', 'cherry', 'date']
7. 日期格式化(指定格式)
适用场景:将Date对象转换为指定格式的日期字符串(如YYYY-MM-DD、HH:MM:SS),适用于时间展示、日志记录等。
// 核心单行函数(格式化YYYY-MM-DD HH:MM:SS)
const formatDate = (date = new Date()) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,补0
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
};
// 调用函数
console.log(formatDate()); // 结果: 2026-04-10 14:30:00(当前时间)
console.log(formatDate(new Date(2026, 3, 10))); // 结果: 2026-04-10 00:00:00
8. 字符串数组与数字数组互换
适用场景:快速转换数组元素类型,适用于数据格式转换(如接口返回字符串数组,需转为数字进行计算)。
// 案例1:数字数组转为字符串数组
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const strArr = arr.map(String);
// 结果: ['1', '2', '3', '4', '5', '6', '7', '8', '9']
// 案例2:字符串数组转为数字数组
var a = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
const numArr = a.map(Number);
// 结果: [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 补充案例(处理异常值)
var b = ['1', '2', 'abc', '4'];
const numArr2 = b.map(Number);
// 结果: [1, 2, NaN, 4](无法转换的字符串会转为NaN)
9. 对象数组匹配更新指定元素
适用场景:根据条件更新对象数组中的指定元素,适用于待办状态修改、数据编辑等前端高频场景。
const todos = [
{ id: '001', name: '吃饭', done: true },
{ id: '002', name: '睡觉', done: true }
];
const id = '002';
const done = false;
const newTodos = todos.map((todoObj) => {
// 匹配id,更新done状态,其余元素不变
if (todoObj.id === id) return { ...todoObj, done };
else return todoObj;
});
// 结果: newTodos = [
// { id: '001', name: '吃饭', done: true },
// { id: '002', name: '睡觉', done: false }
// ]
10. 对象数组删除指定元素
适用场景:过滤删除对象数组中指定条件的元素,适用于待办删除、无效数据清理等场景。
const todos = [
{ id: '001', name: '吃饭', done: true },
{ id: '002', name: '睡觉', done: true }
];
const id = '002';
// 核心代码:过滤掉id为002的元素
const newTodos = todos.filter((todoObj) => todoObj.id !== id);
// 结果: newTodos = [
// { id: '001', name: '吃饭', done: true }
// ]
11. 对象数组查找指定元素
适用场景:根据key快速查找对象数组中符合条件的元素,适用于详情页数据获取、数据查询等场景。
const items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
];
const key = 2; // 要查找的id
// 核心代码:找到id为2的对象
const item = items.find(item => item.id === key);
console.log(item); // 结果: { id: 2, name: 'Item 2' }
12. 对象数组查找指定元素索引
适用场景:快速获取符合条件的元素在数组中的索引,适用于修改、删除指定位置的元素。
const contents = [
{ language: 'zh_CN', alias: "", description: "" },
{ language: 'td_CN', alias: "", description: "" },
{ language: 'en_US', alias: "", description: "" },
{ language: 'ja_JP', alias: "", description: "" }
];
// 核心代码:查找language为zh_CN的元素索引
const index = contents.findIndex(item => item.language === 'zh_CN');
console.log(index); // 结果: 0(数组索引从0开始)
13. 对象数组过滤非空属性元素
适用场景:筛选出对象数组中指定属性不为空的元素,适用于有效数据筛选、表单数据校验等场景。
const contents = [
{ language: 'zh_CN', alias: "1", description: "" },
{ language: 'td_CN', alias: "", description: "" },
{ language: 'en_US', alias: "", description: "" },
{ language: 'ja_JP', alias: "", description: "" }
];
// 核心代码:过滤出alias值不为空的元素
const filteredContents = contents.filter(item => item.alias !== "");
console.log(filteredContents);
// 结果: [{ "language": "zh_CN", "alias": "1", "description": "" }]
14. 对象数组求交集(根据属性匹配)
适用场景:获取两个对象数组中属性匹配的元素,适用于数据对比、重复数据筛选等场景。
let todos1 = [
{ id: "001", name: "吃饭", done: true },
{ id: "002", name: "睡觉", done: true },
];
let todos2 = [
{ id: "001", name: "吃饭", done: true },
{ id: "002", name: "睡觉", done: true },
{ id: "003", name: "学习", done: true },
];
// 核心代码:找出todos2中与todos1 id匹配的元素
todos2 = todos2.filter((item1) =>
todos1.some((item2) => item2.id === item1.id)
);
console.log(todos2);
// 结果: [
// { id: "001", name: "吃饭", done: true },
// { id: "002", name: "睡觉", done: true }
// ]
15. 数组头部添加元素(不修改原数组)
const todos = [
{ id: '001', name: '吃饭', done: true },
{ id: '002', name: '睡觉', done: true }
];
const todoObj = { id: '003', name: '敲码', done: true };
const newTodos = [todoObj, ...todos]; // 核心代码
// 结果: newTodos = [
// { id: '003', name: '敲码', done: true },
// { id: '001', name: '吃饭', done: true },
// { id: '002', name: '睡觉', done: true }
// ]
16. 删除数组指定下标的元素(2种常用方式)
适用场景:明确知道数组中要删除元素的下标,需删除指定位置元素(如删除列表指定索引项、清理数组特定位置无效数据),前端开发高频场景。
// 方式1:splice方法(修改原数组,简洁高效,最常用)
const arr1 = [10, 20, 30, 40, 50];
const index1 = 2; // 要删除的下标(删除元素30)
arr1.splice(index1, 1); // 核心代码:参数1=下标,参数2=删除个数
// 结果: arr1 = [10, 20, 40, 50](原数组被修改)
// 方式2:slice方法(不修改原数组,生成新数组,推荐需保留原数组场景)
const arr2 = [10, 20, 30, 40, 50];
const index2 = 2;
const newArr2 = arr2.slice(0, index2).concat(arr2.slice(index2 + 1)); // 核心代码
// 结果: newArr2 = [10, 20, 40, 50],arr2仍为[10, 20, 30, 40, 50](原数组不变)
// 补充:边界处理(下标越界时,两种方式均不报错,splice无操作,slice返回原数组)
const arr3 = [10, 20];
const index3 = 5; // 下标越界
arr3.splice(index3, 1); // 无操作,arr3仍为[10, 20]
const newArr3 = arr3.slice(0, index3).concat(arr3.slice(index3 + 1)); // newArr3 = [10, 20]
// 补充案例(对象数组删除指定下标元素)
const objArr = [
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' },
{ id: 3, name: '橙子' }
];
const objIndex = 1; // 删除下标为1的“香蕉”
// 方式1(修改原数组)
objArr.splice(objIndex, 1);
// 结果: objArr = [{ id: 1, name: '苹果' }, { id: 3, name: '橙子' }]
// 方式2(不修改原数组)
const newObjArr = objArr.slice(0, objIndex).concat(objArr.slice(objIndex + 1));
// 结果: newObjArr = [{ id: 1, name: '苹果' }, { id: 3, name: '橙子' }]
总结:两种方式各有适用场景——splice方法修改原数组,代码简洁,适合无需保留原数组的场景;slice方法不修改原数组,避免污染原始数据,适合需保留原数组(如数据备份、回滚)的场景。注意:下标从0开始,需做好边界判断,避免下标越界导致无效操作。
17. 对象数组多层数据,只保留两层结构
适用场景:处理多层嵌套的对象数组(如接口返回的复杂数据),需简化结构、只保留两层数据(顶层对象 + 一层子对象/子数组),适用于数据展示、表格渲染等无需深层数据的场景,避免冗余数据影响性能。
// 核心函数:递归/遍历处理,只保留两层数据(顶层 + 一层子级)
// 思路:遍历顶层对象数组,仅保留顶层属性和第一层子级,删除子级中的嵌套数据
const keepTwoLayers = (arr) => {
// 遍历顶层数组,处理每个顶层对象
return arr.map(item => {
// 复制顶层对象(避免修改原数据)
const newItem = {...item};
// 遍历顶层对象的每个属性,判断是否为对象/数组(即子级)
for (let key in newItem) {
const value = newItem[key];
// 若子级是对象(非null)或数组,仅保留其自身属性,删除嵌套层级
if (typeof value === 'object' && value !== null) {
// 数组:保留数组元素,但元素若为对象,仅保留其自身属性(不嵌套)
if (Array.isArray(value)) {
newItem[key] = value.map(subItem => {
return typeof subItem === 'object' && subItem !== null ? {...subItem} : subItem;
});
} else {
// 普通对象:仅保留自身属性,删除嵌套属性
newItem[key] = {...value};
}
}
}
return newItem;
});
};
// 示例:多层嵌套对象数组(模拟接口返回的复杂数据)
const complexArr = [
{
id: 1,
name: '商品分类1',
info: {
desc: '电子产品',
detail: { // 三层嵌套,需删除
createTime: '2026-01-01',
updateTime: '2026-04-10'
},
tags: [
{ name: '热门', type: { id: 1, name: '推荐' } }, // 三层嵌套,需删除
{ name: '新品', type: { id: 2, name: '新品' } }
]
}
},
{
id: 2,
name: '商品分类2',
info: {
desc: '生活用品',
detail: { // 三层嵌套,需删除
createTime: '2026-02-01',
updateTime: '2026-04-05'
},
tags: [
{ name: '热销', type: { id: 3, name: '热销' } }
]
}
}
];
// 调用函数,只保留两层结构
const twoLayerArr = keepTwoLayers(complexArr);
console.log(twoLayerArr);
// 结果:
// [
// {
// id: 1,
// name: '商品分类1',
// info: { desc: '电子产品', detail: {}, tags: [ { name: '热门' }, { name: '新品' } ] }
// },
// {
// id: 2,
// name: '商品分类2',
// info: { desc: '生活用品', detail: {}, tags: [ { name: '热销' } ] }
// }
// ]
总结:keepTwoLayers函数通过map遍历顶层对象数组,复制每个顶层对象,再遍历其属性,对对象/数组类型的子级进行处理——数组元素若为对象则仅保留自身属性,普通对象仅保留自身属性,删除所有三层及以上的嵌套数据。该方法可灵活处理各类多层嵌套对象数组,简化数据结构,避免冗余嵌套影响前端渲染性能,适用于表格展示、列表渲染等无需深层数据的场景。
18. 批量修改对象数组的指定属性(批量更新)
适用场景:批量修改对象数组中所有元素的指定属性,或根据条件批量更新属性值,适用于批量操作(如批量修改状态、批量设置默认值),前端开发高频场景。
// 案例1:批量修改所有元素的指定属性(统一设置默认值)
const products = [
{ id: 1, name: '手机', stock: 100, isSale: false },
{ id: 2, name: '电脑', stock: 50, isSale: false },
{ id: 3, name: '平板', stock: 80, isSale: false }
];
// 核心代码:批量将isSale设为true,stock统一减10
const updatedProducts1 = products.map(item => ({
...item,
isSale: true,
stock: item.stock - 10
}));
// 结果:所有商品isSale为true,stock均减少10
// 案例2:根据条件批量修改属性(满足条件的元素才更新)
// 批量将stock>60的商品isSale设为true,其余不变
const updatedProducts2 = products.map(item => {
if (item.stock > 60) {
return {...item, isSale: true};
}
return item; // 不满足条件则返回原对象
});
// 结果:id为1、3的商品isSale为true,id为2的商品保持不变
// 补充:批量修改多个不同属性(按需设置)
const updatedProducts3 = products.map(item => ({
...item,
price: item.id * 1000, // 新增属性并赋值
stock: item.stock > 60 ? item.stock - 10 : item.stock, // 条件赋值
isSale: item.stock > 60 // 条件赋值(布尔值)
}));
console.log(updatedProducts3);
// 结果:所有商品新增price属性,stock按需减少,isSale按条件设置
总结:利用map方法遍历对象数组,通过对象扩展运算符(...)保留原对象属性,同时修改指定属性值,可实现统一批量修改或条件批量修改。该方法不修改原数组,生成新数组,避免污染原始数据,适用于批量操作场景,代码简洁且可复用,是前端批量处理对象数组的常用方式。
三、十大排序算法(前端实战版)
排序算法是前端数据处理的核心基础,以下整理十大常用排序算法,先通过表格对比各算法关键信息,再详细说明核心原理、JS实现代码(简洁可复制)、适用场景及优缺点,贴合前端开发实际需求,避免复杂冗余,重点适配数组排序场景。
| 排序算法 |
核心特点 |
时间复杂度 |
空间复杂度 |
稳定性 |
前端适用场景 |
| 冒泡排序 |
相邻元素对比,逐步冒泡至末尾 |
O(n²) |
O(1) |
稳定 |
少量数据,简单场景 |
| 选择排序 |
每次选最小/大元素,与首位交换 |
O(n²) |
O(1) |
不稳定 |
少量数据,对稳定性无要求 |
| 插入排序 |
分已排序/未排序,逐个插入合适位置 |
O(n²)(接近有序时O(n)) |
O(1) |
稳定 |
少量数据、数据接近有序(如表单排序) |
| 希尔排序 |
插入排序优化,按步长分组排序 |
O(nlogn) |
O(1) |
不稳定 |
中量数据 |
| 快速排序 |
分治法,选基准值分组递归排序 |
O(nlogn) |
O(logn) |
不稳定 |
大量数据,前端最常用 |
| 归并排序 |
分治法,拆分后合并有序子数组 |
O(nlogn) |
O(n) |
稳定 |
大量数据,对稳定性有要求 |
| 堆排序 |
利用大顶堆特性,逐步取出堆顶元素 |
O(nlogn) |
O(1) |
不稳定 |
大量数据,对空间要求严格 |
| 计数排序 |
非比较排序,统计元素次数后重构数组 |
O(n + k)(k为元素范围) |
O(k) |
稳定 |
元素为整数、范围较小(如分数排序) |
| 桶排序 |
非比较排序,分桶排序后合并 |
O(n + k) |
O(n + k) |
稳定 |
元素分布均匀、大量数据(如数据统计) |
| 基数排序 |
非比较排序,按位数依次排序 |
O(n * k)(k为最大数位数) |
O(n + k) |
稳定 |
整数、字符串,大量数据 |
1. 冒泡排序(Bubble Sort)
核心原理:重复遍历数组,每次比较相邻两个元素,将较大元素“冒泡”到数组末尾,逐步完成排序。
// 优化版:添加标志位,无交换时直接退出(提升效率)
const bubbleSort = (arr) => {
const newArr = [...arr]; // 不修改原数组
const len = newArr.length;
for (let i = 0; i < len - 1; i++) {
let hasSwap = false; // 标志位:是否发生交换
for (let j = 0; j < len - 1 - i; j++) {
if (newArr[j] > newArr[j + 1]) {
[newArr[j], newArr[j + 1]] = [newArr[j + 1], newArr[j]]; // 交换元素
hasSwap = true;
}
}
if (!hasSwap) break; // 无交换,说明已排序完成
}
return newArr;
};
// 示例
const arr1 = [3, 1, 4, 1, 5, 9];
console.log(bubbleSort(arr1)); // 结果:[1, 1, 3, 4, 5, 9]
优缺点:简单易理解,空间复杂度低(O(1));时间复杂度O(n²),数据量大时效率极低,适用于少量数据排序。
2. 选择排序(Selection Sort)
核心原理:每次遍历未排序部分,找到最小(或最大)元素,与未排序部分的第一个元素交换,逐步缩小未排序范围。
const selectionSort = (arr) => {
const newArr = [...arr];
const len = newArr.length;
for (let i = 0; i < len - 1; i++) {
let minIndex = i; // 记录最小元素下标
// 找到未排序部分的最小元素
for (let j = i + 1; j < len; j++) {
if (newArr[j] < newArr[minIndex]) {
minIndex = j;
}
}
// 交换最小元素与未排序部分第一个元素
[newArr[i], newArr[minIndex]] = [newArr[minIndex], newArr[i]];
}
return newArr;
};
// 示例
const arr2 = [7, 2, 5, 0, 3];
console.log(selectionSort(arr2)); // 结果:[0, 2, 3, 5, 7]
优缺点:实现简单,空间复杂度O(1);时间复杂度O(n²),不稳定(相同元素可能改变相对位置),适用于数据量小、对稳定性无要求的场景。
3. 插入排序(Insertion Sort)
核心原理:将数组分为“已排序”和“未排序”两部分,每次从无排序部分取一个元素,插入到已排序部分的合适位置。
const insertionSort = (arr) => {
const newArr = [...arr];
const len = newArr.length;
for (let i = 1; i < len; i++) {
const current = newArr[i]; // 未排序部分的当前元素
let j = i - 1; // 已排序部分的最后一个下标
// 找到插入位置
while (j >= 0 && newArr[j] > current) {
newArr[j + 1] = newArr[j]; // 元素后移
j--;
}
newArr[j + 1] = current; // 插入当前元素
}
return newArr;
};
// 示例
const arr3 = [6, 3, 8, 2, 9];
console.log(insertionSort(arr3)); // 结果:[2, 3, 6, 8, 9]
优缺点:稳定排序,数据接近有序时效率极高(时间复杂度接近O(n));时间复杂度O(n²),适用于少量数据、数据接近有序的场景(如表单排序)。
4. 希尔排序(Shell Sort)
核心原理:插入排序的优化版,将数组按“步长”分组,对每组进行插入排序,逐步缩小步长,最终步长为1时完成排序。
const shellSort = (arr) => {
const newArr = [...arr];
const len = newArr.length;
// 步长初始为数组长度的一半,逐步缩小为1
for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
// 对每组进行插入排序
for (let i = gap; i < len; i++) {
const current = newArr[i];
let j = i - gap;
while (j >= 0 && newArr[j] > current) {
newArr[j + gap] = newArr[j];
j -= gap;
}
newArr[j + gap] = current;
}
}
return newArr;
};
// 示例
const arr4 = [10, 5, 12, 3, 7, 1];
console.log(shellSort(arr4)); // 结果:[1, 3, 5, 7, 10, 12]
优缺点:效率高于插入/冒泡/选择排序,时间复杂度O(nlogn);不稳定,适用于中量数据排序。
5. 快速排序(Quick Sort)
核心原理:分治法,选择一个“基准值”,将数组分为“小于基准”“等于基准”“大于基准”三部分,递归对左右两部分排序,效率极高。
// 简洁版:递归实现,基准值选数组中间元素
const quickSort = (arr) => {
if (arr.length <= 1) return arr; // 递归终止条件
const newArr = [...arr];
const midIndex = Math.floor(newArr.length / 2);
const pivot = newArr.splice(midIndex, 1)[0]; // 基准值(删除并获取)
const left = []; // 小于基准的元素
const right = []; // 大于基准的元素
// 分组
for (let item of newArr) {
item < pivot ? left.push(item) : right.push(item);
}
// 递归排序左右两部分,合并结果
return [...quickSort(left), pivot, ...quickSort(right)];
};
// 示例
const arr5 = [8, 3, 1, 7, 0, 10, 2];
console.log(quickSort(arr5)); // 结果:[0, 1, 2, 3, 7, 8, 10]
优缺点:效率极高,时间复杂度O(nlogn);不稳定,空间复杂度O(logn),适用于大量数据排序(前端最常用的排序算法)。
6. 归并排序(Merge Sort)
核心原理:分治法,将数组递归拆分为两个子数组,直到每个子数组只有一个元素,再逐步合并两个有序子数组,最终得到有序数组。
// 合并两个有序数组
const merge = (left, right) => {
const result = [];
let i = 0, j = 0;
// 对比两个数组,按顺序合并
while (i < left.length && j < right.length) {
left[i] < right[j] ? result.push(left[i++]) : result.push(right[j++]);
}
// 合并剩余元素
return [...result, ...left.slice(i), ...right.slice(j)];
};
// 归并排序主函数
const mergeSort = (arr) => {
if (arr.length <= 1) return arr; // 递归终止条件
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid); // 左子数组
const right = arr.slice(mid); // 右子数组
// 递归拆分 + 合并
return merge(mergeSort(left), mergeSort(right));
};
// 示例
const arr6 = [5, 2, 9, 1, 5, 6];
console.log(mergeSort(arr6)); // 结果:[1, 2, 5, 5, 6, 9]
优缺点:稳定排序,时间复杂度O(nlogn);空间复杂度O(n),适用于对稳定性有要求、大量数据的排序场景。
7. 堆排序(Heap Sort)
核心原理:利用堆(大顶堆/小顶堆)的特性,将数组构建为大顶堆(最大值在堆顶),每次取出堆顶元素,再调整堆结构,重复直至排序完成。
// 调整堆结构(大顶堆)
const adjustHeap = (arr, parentIndex, len) => {
const temp = arr[parentIndex]; // 父节点
let childIndex = 2 * parentIndex + 1; // 左子节点下标
while (childIndex < len) {
// 找到左右子节点中较大的一个
if (childIndex + 1 < len && arr[childIndex + 1] > arr[childIndex]) {
childIndex++;
}
// 父节点大于子节点,无需调整
if (temp >= arr[childIndex]) break;
// 子节点上移
arr[parentIndex] = arr[childIndex];
parentIndex = childIndex;
childIndex = 2 * parentIndex + 1;
}
arr[parentIndex] = temp; // 插入父节点到正确位置
};
// 堆排序主函数
const heapSort = (arr) => {
const newArr = [...arr];
const len = newArr.length;
// 1. 构建大顶堆(从最后一个非叶子节点开始调整)
for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {
adjustHeap(newArr, i, len);
}
// 2. 逐步取出堆顶元素,调整堆结构
for (let i = len - 1; i > 0; i--) {
[newArr[0], newArr[i]] = [newArr[i], newArr[0]]; // 堆顶与末尾元素交换
adjustHeap(newArr, 0, i); // 调整剩余堆结构
}
return newArr;
};
// 示例
const arr7 = [3, 9, 2, 10, 4, 7];
console.log(heapSort(arr7)); // 结果:[2, 3, 4, 7, 9, 10]
优缺点:效率高,时间复杂度O(nlogn);不稳定,空间复杂度O(1),适用于大量数据、对空间要求严格的场景。
8. 计数排序(Counting Sort)
核心原理:非比较排序,统计数组中每个元素出现的次数,根据元素大小顺序,依次输出对应次数的元素,适用于元素范围较小的整数数组。
const countingSort = (arr) => {
if (arr.length <= 1) return arr;
const newArr = [...arr];
const max = Math.max(...newArr); // 找到数组最大值
const min = Math.min(...newArr); // 找到数组最小值
const countArr = new Array(max - min + 1).fill(0); // 计数数组
// 统计每个元素出现的次数
for (let item of newArr) {
countArr[item - min]++;
}
// 构建排序后的数组
let index = 0;
for (let i = 0; i < countArr.length; i++) {
while (countArr[i] > 0) {
newArr[index++] = i + min;
countArr[i]--;
}
}
return newArr;
};
// 示例(元素范围较小的整数数组)
const arr8 = [2, 0, 2, 1, 1, 0];
console.log(countingSort(arr8)); // 结果:[0, 0, 1, 1, 2, 2]
优缺点:稳定排序,时间复杂度O(n + k)(k为元素范围);空间复杂度O(k),仅适用于元素为整数、范围较小的场景(如考试分数排序)。
9. 桶排序(Bucket Sort)
核心原理:非比较排序,将数组元素按范围分到不同的“桶”中,对每个桶内的元素进行排序(可使用其他排序算法),最后合并所有桶的元素。
// 桶排序主函数,默认分5个桶
const bucketSort = (arr, bucketCount = 5) => {
if (arr.length <= 1) return arr;
const newArr = [...arr];
const max = Math.max(...newArr);
const min = Math.min(...newArr);
const bucketSize = Math.ceil((max - min + 1) / bucketCount); // 每个桶的范围大小
const buckets = new Array(bucketCount).fill(0).map(() => []); // 初始化桶
// 将元素分到对应桶中
for (let item of newArr) {
const bucketIndex = Math.floor((item - min) / bucketSize);
buckets[bucketIndex].push(item);
}
// 对每个桶排序,合并结果(这里使用插入排序,也可替换为快速排序)
return buckets.reduce((result, bucket) => {
return [...result, ...insertionSort(bucket)]; // 复用前面的插入排序
}, []);
};
// 示例
const arr9 = [4, 2, 8, 1, 5, 7, 3, 6];
console.log(bucketSort(arr9)); // 结果:[1, 2, 3, 4, 5, 6, 7, 8]
优缺点:稳定排序,时间复杂度O(n + k);空间复杂度O(n + k),适用于元素分布均匀、大量数据的排序场景(如数据统计)。
10. 基数排序(Radix Sort)
核心原理:非比较排序,按元素的“位数”(个位、十位、百位...)依次排序,从低位到高位,每次排序后元素按当前位数有序,最终得到完整有序数组。
// 获取数字的某一位(个位=0,十位=1,百位=2...)
const getDigit = (num, digit) => {
return Math.floor(Math.abs(num) / Math.pow(10, digit)) % 10;
};
// 基数排序主函数
const radixSort = (arr) => {
if (arr.length <= 1) return arr;
const newArr = [...arr];
// 找到数组中最大数的位数
const maxDigit = Math.max(...newArr).toString().length;
// 按每一位排序,从个位到最高位
for (let digit = 0; digit< maxDigit; digit++) {
const buckets = new Array(10).fill(0).map(() => []); // 0-9共10个桶
// 按当前位数将元素分到对应桶中
for (let item of newArr) {
const bucketIndex = getDigit(item, digit);
buckets[bucketIndex].push(item);
}
// 合并桶,更新数组
newArr.splice(0, newArr.length, ...buckets.flat());
}
return newArr;
};
// 示例(正整数数组)
const arr10 = [123, 45, 6, 789, 10, 23];
console.log(radixSort(arr10)); // 结果:[6, 10, 23, 45, 123, 789]
优缺点:稳定排序,时间复杂度O(n * k)(k为最大数的位数);空间复杂度O(n + k),适用于整数、字符串等可按“位”排序的大量数据场景。
排序算法总结(前端选型参考)
-
少量数据(n < 100):优先用插入排序、冒泡排序(简单易实现);
-
中大量数据(n > 100):优先用快速排序(效率最高)、归并排序(稳定);
-
元素范围小的整数数组:用计数排序、桶排序(效率高于比较排序);
-
对稳定性有要求:用归并排序、插入排序、计数排序、桶排序、基数排序;
-
对空间有要求:用堆排序、快速排序、冒泡排序、选择排序、插入排序、希尔排序。
-
所有代码均为前端实战高频场景,可直接复制到项目中使用,部分代码需根据实际需求(如DOM选择器、属性名)微调;
-
单行代码优先简化实现,兼顾简洁性和实用性,复杂场景补充完整示例,适配不同开发需求;
-
注意浏览器兼容性:部分API(如Clipboard API、可选链运算符??、扩展运算符)不支持IE浏览器,若需兼容IE,需额外做兼容处理;
-
对象/数组操作均优先采用不修改原数据的方式(如扩展运算符、map、filter),避免意外污染原始数据,提升代码可维护性。