news 2026/5/1 5:43:06

JavaScript 原生 sort() 方法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript 原生 sort() 方法详解

JavaScript 原生sort()方法详解

一、基本语法

javascript

// 语法 arr.sort([compareFunction]) // 返回值:排序后的原数组(原地修改) const sortedArray = arr.sort(compareFunction);

二、默认行为(不使用比较函数)

1.字符串排序(默认)

javascript

const fruits = ['banana', 'apple', 'cherry', 'date']; fruits.sort(); console.log(fruits); // ['apple', 'banana', 'cherry', 'date'] const numbersAsStrings = ['10', '2', '1', '20']; numbersAsStrings.sort(); console.log(numbersAsStrings); // ['1', '10', '2', '20'] ⚠️ 按字符串排序

2.数字排序问题

javascript

const numbers = [10, 2, 1, 20]; numbers.sort(); console.log(numbers); // [1, 10, 2, 20] ❌ 不是数字顺序! // 这是因为 sort() 默认将元素转换为字符串比较 // 比较过程:"10" < "2" // true(按字典序比较)

三、比较函数详解

1.基本数字排序

javascript

// 升序排序 arr.sort((a, b) => a - b); // 降序排序 arr.sort((a, b) => b - a); // 完整示例 const numbers = [40, 100, 1, 5, 25, 10]; numbers.sort((a, b) => a - b); console.log(numbers); // [1, 5, 10, 25, 40, 100] numbers.sort((a, b) => b - a); console.log(numbers); // [100, 40, 25, 10, 5, 1]

2.比较函数工作原理

javascript

// 比较函数应该返回: // - 负数:a 排在 b 前面 // - 零:a 和 b 相对位置不变 // - 正数:a 排在 b 后面 function compare(a, b) { if (a < b) { return -1; // a 在前 } if (a > b) { return 1; // a 在后 } return 0; // 位置不变 } // 简化版(仅适用于数字) function compareNumbers(a, b) { return a - b; // 升序 }

四、V8 引擎实现原理

1.使用的算法:Timsort

javascript

// Timsort = Tim Peters' sort = 归并排序 + 插入排序优化 // 特点: // 1. 稳定排序(相等元素保持原顺序) // 2. 自适应(根据数据特征选择策略) // 3. 时间复杂度:O(n log n) // 4. 空间复杂度:O(n) // 工作原理: // 1. 寻找"run"(已经有序的片段) // 2. 小片段使用插入排序 // 3. 使用归并排序合并片段 // 4. 优化内存使用(原地归并或临时数组)

2.性能特征

javascript

// 不同数据规模的性能表现 const dataSizes = [100, 1000, 10000, 100000, 1000000]; // Timsort 对以下情况特别优化: // 1. 部分有序数组 // 2. 包含重复元素的数组 // 3. 逆序数组 // 4. 随机数组 // 在 Chrome 中的实际表现: // - 小数组(< 10):插入排序 // - 中等数组:快速排序变体 // - 大数组:Timsort

五、复杂对象排序

1.按对象属性排序

javascript

const users = [ { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }, { name: 'Charlie', age: 35 } ]; // 按年龄升序 users.sort((a, b) => a.age - b.age); // 按名字字母顺序 users.sort((a, b) => a.name.localeCompare(b.name)); // 多条件排序 users.sort((a, b) => { if (a.age !== b.age) { return a.age - b.age; // 先按年龄 } return a.name.localeCompare(b.name); // 年龄相同按名字 });

2.自定义排序规则

javascript

const priorities = ['high', 'medium', 'low']; const tasks = [ { title: 'Task A', priority: 'medium' }, { title: 'Task B', priority: 'high' }, { title: 'Task C', priority: 'low' } ]; tasks.sort((a, b) => { return priorities.indexOf(a.priority) - priorities.indexOf(b.priority); }); // 结果:high -> medium -> low

六、特殊排序需求

1.中文排序

javascript

const chineseNames = ['张三', '李四', '王五', '赵六']; // 简单排序(Unicode顺序) chineseNames.sort(); console.log(chineseNames); // Unicode 顺序 // 正确的中文拼音排序 chineseNames.sort((a, b) => a.localeCompare(b, 'zh-CN')); console.log(chineseNames); // 按拼音排序 // 支持更多选项 chineseNames.sort((a, b) => a.localeCompare(b, 'zh-CN', { sensitivity: 'base', // 忽略大小写和重音 numeric: true // 数字作为数字比较 }) );

2.带单位的字符串排序

javascript

const sizes = ['10px', '2px', '100px', '50px']; sizes.sort((a, b) => { const numA = parseInt(a); const numB = parseInt(b); return numA - numB; }); console.log(sizes); // ['2px', '10px', '50px', '100px']

3.日期排序

javascript

const dates = [ '2024-01-15', '2023-12-01', '2024-02-20', '2023-11-10' ]; dates.sort((a, b) => new Date(a) - new Date(b)); // 或 dates.sort((a, b) => a.localeCompare(b)); // 字符串比较也适用

七、性能优化技巧

1.缓存比较结果

javascript

// 优化前(每次比较都计算) const complexObjects = [...]; // 大量复杂对象 complexObjects.sort((a, b) => calculateComplexValue(a) - calculateComplexValue(b) ); // 优化后(Schwartzian transform) complexObjects .map(obj => ({ original: obj, value: calculateComplexValue(obj) })) .sort((a, b) => a.value - b.value) .map(item => item.original);

2.避免在比较函数中创建对象

javascript

// 不好:每次比较都创建新对象 arr.sort((a, b) => { const dateA = new Date(a.timestamp); const dateB = new Date(b.timestamp); return dateA - dateB; }); // 好:预先处理 arr.forEach(item => { item._sortDate = new Date(item.timestamp); }); arr.sort((a, b) => a._sortDate - b._sortDate); arr.forEach(item => delete item._sortDate);

八、常见陷阱

1.原地修改问题

javascript

const original = [3, 1, 4, 1, 5]; const sorted = original.sort(); console.log(original); // [1, 1, 3, 4, 5] ❌ 原数组被修改了! console.log(sorted); // [1, 1, 3, 4, 5] 同一个数组 // 正确做法:先复制 const safeSorted = [...original].sort(); // 或 const safeSorted = original.slice().sort();

2.不稳定的比较函数

javascript

// 错误的比较函数(可能引起问题) [1, 2, 3, 4, 5].sort(() => Math.random() - 0.5); // 这不保证均匀分布,也不高效 // 正确洗牌算法(Fisher-Yates) function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; }

3.NaN 处理

javascript

const arr = [1, NaN, 3, 2, NaN, 4]; arr.sort((a, b) => a - b); console.log(arr); // [1, 2, 3, 4, NaN, NaN] // NaN 被排到最后 // 自定义 NaN 处理 arr.sort((a, b) => { if (isNaN(a) && isNaN(b)) return 0; if (isNaN(a)) return 1; // NaN 在后 if (isNaN(b)) return -1; // 非NaN在前 return a - b; });

九、高级应用

1.稳定排序模拟

javascript

// 如果需要绝对稳定(旧浏览器),可以添加索引 const data = [{value: 2}, {value: 1}, {value: 2}]; data .map((item, index) => ({item, index})) .sort((a, b) => { const valueDiff = a.item.value - b.item.value; if (valueDiff !== 0) return valueDiff; return a.index - b.index; // 保持原顺序 }) .map(({item}) => item);

2.多维度动态排序

javascript

function dynamicSort(properties) { return function(a, b) { for (const {property, order = 'asc'} of properties) { const aVal = a[property]; const bVal = b[property]; if (aVal < bVal) return order === 'asc' ? -1 : 1; if (aVal > bVal) return order === 'asc' ? 1 : -1; } return 0; }; } const items = [...]; items.sort(dynamicSort([ {property: 'category', order: 'asc'}, {property: 'price', order: 'desc'}, {property: 'name', order: 'asc'} ]));

3.性能基准测试

javascript

function benchmarkSort(arr, sortFn, iterations = 100) { const times = []; for (let i = 0; i < iterations; i++) { const copy = [...arr]; const start = performance.now(); sortFn(copy); const end = performance.now(); times.push(end - start); } return { avg: times.reduce((a, b) => a + b) / times.length, min: Math.min(...times), max: Math.max(...times), stdDev: Math.sqrt( times.map(t => Math.pow(t - avg, 2)) .reduce((a, b) => a + b) / times.length ) }; }

十、总结

最佳实践:

  1. 始终提供比较函数(除非明确需要字符串排序)

  2. 注意原地修改- 必要时先复制数组

  3. 复杂比较预计算- 提高性能

  4. 利用稳定性- 多条件排序依赖稳定排序特性

  5. 考虑数据特性- 部分有序数据 Timsort 表现更好


选择sort()当:

  • 需要稳定排序

  • 处理复杂对象

  • 代码简洁性优先

  • 数组大小适中(< 1百万)


考虑其他方案当:

  • 需要绝对性能(TypedArray)

  • 内存极度受限(堆排序)

  • 特殊数据结构(如链表)

  • 只需要部分排序(选择算法)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/26 9:11:11

FastMCP之Resources

一、什么是资源 资源代表 MCP 客户端可以读取的数据或文件&#xff0c;而资源模板通过允许客户端基于 URI 中传递的参数请求动态生成的资源&#xff0c;扩展了这一概念。 FastMCP 简化了静态和动态资源的定义&#xff0c;主要使用 mcp.resource 装饰器。 当客户端请求资源统一资…

作者头像 李华
网站建设 2026/4/20 11:23:15

php反序列化学习

php反序列化学习在PHP中&#xff0c;反序列化漏洞&#xff08;也称为PHP对象注入漏洞&#xff09;是一个安全漏洞&#xff0c;它允许攻击者执行恶意代码或者访问敏感数据。这种漏洞通常发生在应用程序不正确地处理来自不可靠来源的序列化数据时就是将对象的状态信息写成一串字符…

作者头像 李华
网站建设 2026/4/21 18:43:56

为什么越来越多项目开始从 JDK 8 升级到 JDK 21?

从 JDK 8 升级到 JDK 21&#xff1a;哪些新特性真的好用&#xff1f;一篇写给 Java 工程师的实战指南先给结论&#xff1a; JDK 8 之后的升级&#xff0c;并不是语法糖的简单堆叠&#xff0c;而是一次并发模型、性能体系、代码表达能力的系统性进化。 JDK 21 作为最新 LTS&…

作者头像 李华
网站建设 2026/4/28 21:47:20

uniapp 实现路由切或者tab切换详细步骤

uniapp 实现路由切或者tab切换详细步骤 在 UniApp 中实现页面路由和标签页&#xff08;Tab&#xff09;切换是核心开发技能。下面为你梳理详细步骤和不同场景的实践方案。 下面表格中帮助你快速了解 UniApp 中主要的页面跳转方式及其区别&#xff1a;跳转方法作用适用场景关键限…

作者头像 李华