前端必看!JS高频实用案例(单行代码+实战场景+十大排序)

一、JS单行高频实用案例(25个,直接复制可用)

1. 变量值交换(不使用临时变量)

适用场景:快速交换两个变量的值,无需额外声明临时变量,简化代码,适用于简单值交换场景。

ini 复制代码
// 核心单行代码(适用于数字、字符串等基本类型)
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. 快速生成随机数(指定范围)

适用场景:生成指定区间内的随机整数(如随机抽奖、随机排序、模拟随机数据),前端高频使用场景。

arduino 复制代码
// 核心单行代码(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. 浅克隆对象(复制顶层属性)

适用场景:快速复制对象的顶层属性,生成新对象,适用于简单对象(无嵌套对象)的复制,避免修改原对象。

ini 复制代码
const originalObj = { name: '张三', age: 24 }; // 修正原文档拼写错误(original0bj→originalObj)
const clonedObj = { ...originalObj }; // 核心单行代码
// 结果: clonedObj = { name: '张三', age: 24 }
// 验证:修改clonedObj.age = 25,originalObj.age仍为24

总结:利用扩展运算符(...)复制对象的所有可枚举自身属性,生成新对象。注意:若对象包含嵌套对象,嵌套对象仍为引用类型,修改嵌套对象会影响原对象,此时需使用深克隆。

4. 合并对象

适用场景:将多个对象合并为一个新对象,重复属性会被后一个对象覆盖。

ini 复制代码
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. 清理数组(删除所有假值)

适用场景:快速过滤数组中的假值,保留有效数据。

ini 复制代码
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)操作时。

dart 复制代码
// 修正原文档语法疏漏(补充扩展运算符包裹)
const nodesArray = [...document.querySelectorAll('div')]; 
// 结果: nodesArray 为包含所有div元素的数组,可使用map、filter等方法

总结:扩展运算符可将类数组(NodeList、arguments等)转换为真正的数组,从而使用数组的所有方法。例如:nodesArray.map(div => div.style.color = 'red'),可批量修改所有div的字体颜色。

7. 检查数组是否满足指定条件

适用场景:判断数组中是否存在满足条件的元素(some),或所有元素是否都满足条件(every)。

ini 复制代码
// 案例1:检查数组中是否存在负数
const arr1 = [1, 2, 3, -5, 4];&#xA;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. 将文本复制到剪贴板

适用场景:实现点击按钮复制文本、复制链接等功能。

dart 复制代码
// 核心单行代码(异步操作,可结合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. 删除数组重复项

适用场景:快速去重,适用于基本数据类型(数字、字符串、布尔值等)的数组。

ini 复制代码
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. 取两个数组的交集

适用场景:获取两个数组中共同存在的元素。

ini 复制代码
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. 求数组元素的总和

适用场景:快速计算数组中所有基本数据类型(数字)的总和。

ini 复制代码
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语句。

ini 复制代码
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. 使用变量作为对象的键

适用场景:动态设置对象的键名(键名不确定,需通过变量指定)。

ini 复制代码
const dynamicKey = 'name';
const value = '张三';
const obj = { [dynamicKey]: value }; // 核心单行代码(计算属性名)
// 结果: obj = { name: '张三' }

// 补充案例(动态切换键名)
const dynamicKey2 = 'age';
const obj2 = { [dynamicKey2]: 24 };
// 结果: obj2 = { age: 24 }

总结:通过计算属性名(方括号包裹变量),可将变量的值作为对象的键名,灵活适配动态场景,例如根据接口返回值动态设置对象键名。

14. 离线状态检查器

适用场景:检测用户浏览器的网络连接状态,提示用户当前是否在线。

javascript 复制代码
const isOnline = navigator.onLine ? '在线' : '离线'; // 核心单行代码
// 结果: 网络正常时返回'在线',断开时返回'离线'

// 完整示例(实时监听网络状态)
window.addEventListener('online', () => console.log('网络已连接,当前状态:在线'));
window.addEventListener('offline', () => console.log('网络已断开,当前状态:离线'));

总结:利用navigator.onLine属性结合三元运算符,快速判断网络状态。注意:navigator.onLine仅能检测是否有网络连接,无法判断网络是否能正常访问互联网(如连接了无网络的WiFi)。

15. 离开页面弹出确认对话框

适用场景:防止用户误操作关闭页面,导致未保存的数据丢失(如表单填写、编辑内容)。

ini 复制代码
// 核心单行代码
window.onbeforeunload = () => '你确定要离开吗?未保存的内容将丢失!'; // 补充提示信息

// 补充:现代浏览器对提示文本的限制(部分浏览器不显示自定义文本,仅显示默认提示)
window.onbeforeunload = (e) => {
  e.preventDefault();
  e.returnValue = '';
  return '你确定要离开吗?';
};

总结:监听window的onbeforeunload事件,当用户关闭页面、刷新页面或跳转页面时,会弹出确认对话框。注意:现代浏览器为了安全,可能会忽略自定义提示文本,仅显示浏览器默认提示。

16. 对象数组,根据对象的某个key求对应值的总和

适用场景:统计对象数组中,指定属性的所有值的总和(如统计订单金额、商品数量等)。

ini 复制代码
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中的查询参数,方便获取参数值(如页面跳转传参、接口请求参数解析)。

ini 复制代码
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)

适用场景:将秒数转换为标准时间格式,如视频时长、倒计时显示等。

ini 复制代码
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. 求某对象所有属性值的最大值

适用场景:快速获取对象中所有属性值的最大值(如统计最高分、最大金额等)。

ini 复制代码
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. 判断对象的值中是否包含某个值

适用场景:检查对象的所有属性值中,是否存在指定的值。

ini 复制代码
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错误。

ini 复制代码
// 案例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语句,简洁实现"条件为真时执行函数/赋值"。

ini 复制代码
// 案例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. 创建包含指定数字范围的数组

适用场景:快速生成连续数字数组(如分页页码、循环计数等)。

javascript 复制代码
// 案例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. 提取文件扩展名

适用场景:获取文件名中的扩展名(如判断文件类型、上传文件校验等)。

ini 复制代码
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(如菜单显示/隐藏、按钮选中/取消、表单状态切换等)。

dart 复制代码
// 核心代码(修正原文档语法错误,补充括号)
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、滚动等高频事件频繁触发函数,适用于搜索联想、输入验证等场景。

javascript 复制代码
// 核心单行防抖函数(简化版)
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. 节流函数(限制函数触发频率)

适用场景:限制函数在指定时间内只能触发一次,适用于滚动加载、按钮点击防重复提交等场景。

ini 复制代码
// 核心单行节流函数(简化版)
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. 深克隆对象(解决嵌套对象复制问题)

适用场景:复制包含嵌套对象的复杂对象,确保修改克隆对象不影响原对象,适用于数据备份、复杂数据处理。

ini 复制代码
// 核心单行深克隆(简单场景,不支持函数、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的局限性,适用于数据校验场景。

css 复制代码
// 核心单行函数
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. 数组扁平化(多维转一维)

适用场景:将多维数组转为一维数组,适用于数据处理、数组遍历等场景,简化数据操作。

scss 复制代码
// 案例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默认字符串排序的问题。

ini 复制代码
// 案例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),适用于时间展示、日志记录等。

javascript 复制代码
// 核心单行函数(格式化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. 字符串数组与数字数组互换

适用场景:快速转换数组元素类型,适用于数据格式转换(如接口返回字符串数组,需转为数字进行计算)。

ini 复制代码
// 案例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. 对象数组匹配更新指定元素

适用场景:根据条件更新对象数组中的指定元素,适用于待办状态修改、数据编辑等前端高频场景。

ini 复制代码
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. 对象数组删除指定元素

适用场景:过滤删除对象数组中指定条件的元素,适用于待办删除、无效数据清理等场景。

ini 复制代码
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快速查找对象数组中符合条件的元素,适用于详情页数据获取、数据查询等场景。

ini 复制代码
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. 对象数组查找指定元素索引

适用场景:快速获取符合条件的元素在数组中的索引,适用于修改、删除指定位置的元素。

csharp 复制代码
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. 对象数组过滤非空属性元素

适用场景:筛选出对象数组中指定属性不为空的元素,适用于有效数据筛选、表单数据校验等场景。

bash 复制代码
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. 对象数组求交集(根据属性匹配)

适用场景:获取两个对象数组中属性匹配的元素,适用于数据对比、重复数据筛选等场景。

bash 复制代码
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. 数组头部添加元素(不修改原数组)

bash 复制代码
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种常用方式)

适用场景:明确知道数组中要删除元素的下标,需删除指定位置元素(如删除列表指定索引项、清理数组特定位置无效数据),前端开发高频场景。

ini 复制代码
// 方式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. 对象数组多层数据,只保留两层结构

适用场景:处理多层嵌套的对象数组(如接口返回的复杂数据),需简化结构、只保留两层数据(顶层对象 + 一层子对象/子数组),适用于数据展示、表格渲染等无需深层数据的场景,避免冗余数据影响性能。

javascript 复制代码
// 核心函数:递归/遍历处理,只保留两层数据(顶层 + 一层子级)
// 思路:遍历顶层对象数组,仅保留顶层属性和第一层子级,删除子级中的嵌套数据
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. 批量修改对象数组的指定属性(批量更新)

适用场景:批量修改对象数组中所有元素的指定属性,或根据条件批量更新属性值,适用于批量操作(如批量修改状态、批量设置默认值),前端开发高频场景。

c 复制代码
// 案例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)

核心原理:重复遍历数组,每次比较相邻两个元素,将较大元素"冒泡"到数组末尾,逐步完成排序。

ini 复制代码
// 优化版:添加标志位,无交换时直接退出(提升效率)
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)

核心原理:每次遍历未排序部分,找到最小(或最大)元素,与未排序部分的第一个元素交换,逐步缩小未排序范围。

ini 复制代码
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)

核心原理:将数组分为"已排序"和"未排序"两部分,每次从无排序部分取一个元素,插入到已排序部分的合适位置。

ini 复制代码
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时完成排序。

ini 复制代码
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)

核心原理:分治法,选择一个"基准值",将数组分为"小于基准""等于基准""大于基准"三部分,递归对左右两部分排序,效率极高。

ini 复制代码
// 简洁版:递归实现,基准值选数组中间元素
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)

核心原理:分治法,将数组递归拆分为两个子数组,直到每个子数组只有一个元素,再逐步合并两个有序子数组,最终得到有序数组。

ini 复制代码
// 合并两个有序数组
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)

核心原理:利用堆(大顶堆/小顶堆)的特性,将数组构建为大顶堆(最大值在堆顶),每次取出堆顶元素,再调整堆结构,重复直至排序完成。

ini 复制代码
// 调整堆结构(大顶堆)
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)

核心原理:非比较排序,统计数组中每个元素出现的次数,根据元素大小顺序,依次输出对应次数的元素,适用于元素范围较小的整数数组。

ini 复制代码
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)

核心原理:非比较排序,将数组元素按范围分到不同的"桶"中,对每个桶内的元素进行排序(可使用其他排序算法),最后合并所有桶的元素。

ini 复制代码
// 桶排序主函数,默认分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)

核心原理:非比较排序,按元素的"位数"(个位、十位、百位...)依次排序,从低位到高位,每次排序后元素按当前位数有序,最终得到完整有序数组。

ini 复制代码
// 获取数字的某一位(个位=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),适用于整数、字符串等可按"位"排序的大量数据场景。

排序算法总结(前端选型参考)

  1. 少量数据(n < 100):优先用插入排序、冒泡排序(简单易实现);

  2. 中大量数据(n > 100):优先用快速排序(效率最高)、归并排序(稳定);

  3. 元素范围小的整数数组:用计数排序、桶排序(效率高于比较排序);

  4. 对稳定性有要求:用归并排序、插入排序、计数排序、桶排序、基数排序;

  5. 对空间有要求:用堆排序、快速排序、冒泡排序、选择排序、插入排序、希尔排序。

  6. 所有代码均为前端实战高频场景,可直接复制到项目中使用,部分代码需根据实际需求(如DOM选择器、属性名)微调;

  7. 单行代码优先简化实现,兼顾简洁性和实用性,复杂场景补充完整示例,适配不同开发需求;

  8. 注意浏览器兼容性:部分API(如Clipboard API、可选链运算符??、扩展运算符)不支持IE浏览器,若需兼容IE,需额外做兼容处理;

  9. 对象/数组操作均优先采用不修改原数据的方式(如扩展运算符、map、filter),避免意外污染原始数据,提升代码可维护性。

相关推荐
前端Hardy2 小时前
前端开发效率翻倍:15个超级实用的工具函数,直接复制进项目(建议收藏)
前端·javascript·面试
前端Hardy2 小时前
Vue 项目必备:10 个高频实用自定义指令,直接复制即用(Vue2 / Vue3 通用)
前端·javascript·vue.js
h_jQuery2 小时前
uniapp使用canvas实现逐字书写任意文字内容,后合成一张图片提交
前端·javascript·uni-app
懒大王95272 小时前
Vue 2 与 Vue 3 的区别
前端·javascript·vue.js
xuankuxiaoyao3 小时前
vue.js 实践--侦听器和样式绑定
前端·javascript·vue.js
AIBox3653 小时前
openclaw api 配置教程,支持 Claude、Gemini、GPT5.4 等模型
javascript·人工智能·gpt
Rattenking3 小时前
uni-app组件开发----自定义数字键盘组件
前端·javascript·uni-app
小沐°3 小时前
vue3+element-plus 实现动态菜单和动态路由的渲染
前端·javascript·vue.js
蓝黑20203 小时前
Vue导入和注册组件
前端·javascript·vue