js?Array?sort實(shí)戰(zhàn)排序全面講解教程
一、sort()方法基礎(chǔ)認(rèn)知
1. 基本定義
sort() 是 JavaScript 數(shù)組原型上的內(nèi)置方法,用于對(duì)數(shù)組元素進(jìn)行排序,并返回排序后的原數(shù)組(注意:它是「原地排序」,會(huì)直接修改原始數(shù)組,而非返回新數(shù)組)。
2. 默認(rèn)排序規(guī)則
sort() 方法如果不傳入任何參數(shù),會(huì)按照「字符串 Unicode 編碼」進(jìn)行排序,而非我們直覺(jué)中的數(shù)字大小排序,這是新手最容易踩坑的點(diǎn)。
示例:默認(rèn)排序的表現(xiàn)
// 1. 字符串?dāng)?shù)組(符合直覺(jué),按Unicode排序) const strArr = ["banana", "apple", "cherry", "Abc"]; strArr.sort(); console.log(strArr); // ["Abc", "apple", "banana", "cherry"] // 原因:Unicode 中大寫字母編碼(A-Z:65-90)小于小寫字母(a-z:97-122) // 2. 數(shù)字?jǐn)?shù)組(不符合直覺(jué),按字符串Unicode排序) const numArr = [10, 2, 31, 4, 25]; numArr.sort(); console.log(numArr); // [10, 2, 25, 31, 4] // 原因:數(shù)字會(huì)被先轉(zhuǎn)為字符串,"10"的Unicode編碼小于"2",因此10排在2前面
二、sort()核心:比較函數(shù)(compareFunction)
要實(shí)現(xiàn)按數(shù)字大小、對(duì)象屬性等自定義規(guī)則排序,必須給 sort() 傳入一個(gè)比較函數(shù)((a, b) => {}),這是 sort() 方法的靈魂。
1. 比較函數(shù)的參數(shù)與返回值規(guī)則
比較函數(shù)接收兩個(gè)必選參數(shù) a 和 b(代表數(shù)組中任意兩個(gè)待比較的元素,a 是后一個(gè)元素,b 是前一個(gè)元素),返回值的類型決定了排序結(jié)果:
| 比較函數(shù)返回值 | 排序規(guī)則 |
|---|---|
返回 負(fù)數(shù)(< 0) | a 排在 b 前面(升序邏輯) |
| 返回 0 | a 和 b 位置不變(穩(wěn)定排序的關(guān)鍵) |
返回 正數(shù)(> 0) | a 排在 b 后面(降序邏輯) |
2. 數(shù)字?jǐn)?shù)組的正/降序排序(最常用場(chǎng)景)
(1)數(shù)字升序排序
const numArr = [10, 2, 31, 4, 25]; // 比較函數(shù):a - b 實(shí)現(xiàn)升序 numArr.sort((a, b) => a - b); console.log(numArr); // [2, 4, 10, 25, 31] // 原理:若a < b,a - b為負(fù)數(shù),a排在b前面;若a > b,a - b為正數(shù),a排在b后面
(2)數(shù)字降序排序
const numArr = [10, 2, 31, 4, 25]; // 比較函數(shù):b - a 實(shí)現(xiàn)降序 numArr.sort((a, b) => b - a); console.log(numArr); // [31, 25, 10, 4, 2] // 原理:若b > a,b - a為正數(shù),a排在b后面(即大的數(shù)排在前面)
三、常見(jiàn)場(chǎng)景實(shí)戰(zhàn)排序
1. 字符串?dāng)?shù)組:忽略大小寫排序
默認(rèn)排序會(huì)區(qū)分大小寫,通過(guò)將元素統(tǒng)一轉(zhuǎn)為大寫/小寫后比較,可實(shí)現(xiàn)忽略大小寫的排序:
const strArr = ["banana", "Apple", "cherry", "abc"];
strArr.sort((a, b) => {
const lowerA = a.toLowerCase();
const lowerB = b.toLowerCase();
if (lowerA < lowerB) return -1; // 升序
if (lowerA > lowerB) return 1;
return 0;
});
console.log(strArr); // ["Apple", "abc", "banana", "cherry"]
2. 字符串?dāng)?shù)組:按長(zhǎng)度排序
const strArr = ["banana", "apple", "cherry", "a"];
// 先按長(zhǎng)度升序,長(zhǎng)度相同按Unicode升序
strArr.sort((a, b) => {
if (a.length !== b.length) {
return a.length - b.length; // 長(zhǎng)度升序
}
return a.localeCompare(b); // 長(zhǎng)度相同,按自然語(yǔ)言排序(比直接比較字符串更友好)
});
console.log(strArr); // ["a", "apple", "banana", "cherry"]
3. 對(duì)象數(shù)組:按單個(gè)屬性排序
日常開(kāi)發(fā)中最常用的場(chǎng)景,比如按用戶年齡、商品價(jià)格排序:
// 用戶數(shù)組
const users = [
{ name: "張三", age: 25, salary: 8000 },
{ name: "李四", age: 20, salary: 10000 },
{ name: "王五", age: 30, salary: 7000 },
];
// (1)按年齡升序排序
users.sort((a, b) => a.age - b.age);
console.log(users.map(u => u.name)); // ["李四", "張三", "王五"]
// (2)按薪資降序排序
users.sort((a, b) => b.salary - a.salary);
console.log(users.map(u => u.name)); // ["李四", "張三", "王五"]
// (3)按姓名自然語(yǔ)言排序(中文排序)
users.sort((a, b) => a.name.localeCompare(b.name, "zh-CN"));
console.log(users.map(u => u.name)); // ["李四", "王五", "張三"]
4. 對(duì)象數(shù)組:多條件排序
當(dāng)?shù)谝粋€(gè)排序條件相同時(shí),按第二個(gè)條件排序(比如:先按年齡升序,年齡相同按薪資降序):
const users = [
{ name: "張三", age: 25, salary: 8000 },
{ name: "李四", age: 20, salary: 10000 },
{ name: "趙六", age: 25, salary: 9000 },
{ name: "王五", age: 30, salary: 7000 },
];
users.sort((a, b) => {
// 第一個(gè)條件:年齡升序
if (a.age !== b.age) {
return a.age - b.age;
}
// 第二個(gè)條件:薪資降序(年齡相同時(shí)生效)
return b.salary - a.salary;
});
console.log(users.map(u => `${u.name}(${u.age}歲,${u.salary}元)`));
// 輸出:
// ["李四(20歲,10000元)", "趙六(25歲,9000元)", "張三(25歲,8000元)", "王五(30歲,7000元)"]
5. 包含特殊值(null/undefined)的數(shù)組排序
sort() 會(huì)自動(dòng)將 undefined 排到數(shù)組末尾;null 轉(zhuǎn)為數(shù)字是 0,可手動(dòng)處理其排序位置:
const mixedArr = [10, null, 5, undefined, 3, null, 8];
mixedArr.sort((a, b) => {
// 處理undefined:直接排到末尾
if (a === undefined) return 1;
if (b === undefined) return -1;
// 處理null:按0參與數(shù)字升序排序
return (a ?? 0) - (b ?? 0);
});
console.log(mixedArr); // [null, null, 3, 5, 8, 10, undefined]
四、進(jìn)階知識(shí)點(diǎn):穩(wěn)定排序
1. 穩(wěn)定排序的定義
如果數(shù)組中兩個(gè)相等的元素(按比較函數(shù)判斷返回 0),在排序前后的相對(duì)位置保持不變,這種排序就是「穩(wěn)定排序」。
2.sort()的穩(wěn)定性
- ES6(ECMAScript 2015)及以后:
sort()方法實(shí)現(xiàn)了穩(wěn)定排序(不同瀏覽器內(nèi)核實(shí)現(xiàn)一致)。 - ES6 之前:
sort()是不穩(wěn)定排序,不同瀏覽器表現(xiàn)可能不同。
示例:驗(yàn)證穩(wěn)定排序
// 商品數(shù)組:按價(jià)格升序(價(jià)格相同的商品,保持原有相對(duì)位置)
const goods = [
{ name: "商品A", price: 50 },
{ name: "商品B", price: 30 }, // 先出現(xiàn)
{ name: "商品C", price: 50 },
{ name: "商品D", price: 30 }, // 后出現(xiàn)
];
// 按價(jià)格升序排序
goods.sort((a, b) => a.price - b.price);
console.log(goods.map(g => g.name)); // ["商品B", "商品D", "商品A", "商品C"]
// 結(jié)果:價(jià)格30的商品B仍在商品D前面,價(jià)格50的商品A仍在商品C前面,驗(yàn)證了穩(wěn)定排序
五、常見(jiàn)誤區(qū)與避坑技巧
1. 誤區(qū)1:忽略「原地排序」,誤認(rèn)返回新數(shù)組
sort() 會(huì)修改原始數(shù)組,返回的是原始數(shù)組的引用,而非新數(shù)組。如果需要保留原始數(shù)組,應(yīng)先拷貝數(shù)組再排序。
避坑示例:
const originalArr = [10, 2, 31]; // 先拷貝數(shù)組(推薦使用擴(kuò)展運(yùn)算符或slice(),淺拷貝即可) const sortedArr = [...originalArr].sort((a, b) => a - b); console.log(originalArr); // [10, 2, 31](原始數(shù)組未被修改) console.log(sortedArr); // [2, 10, 31](排序后的新數(shù)組)
2. 誤區(qū)2:數(shù)字排序不傳入比較函數(shù)
新手常直接對(duì)數(shù)字?jǐn)?shù)組使用 sort(),導(dǎo)致排序結(jié)果不符合預(yù)期,必須傳入 (a, b) => a - b(升序)或 (a, b) => b - a(降序)。
3. 誤區(qū)3:比較函數(shù)返回非數(shù)字類型
比較函數(shù)的返回值應(yīng)是數(shù)字(負(fù)數(shù)/0/正數(shù)),若返回布爾值或其他類型,會(huì)被隱式轉(zhuǎn)為數(shù)字(true→1,false→0),可能導(dǎo)致排序異常。
錯(cuò)誤示例 vs 正確示例:
const numArr = [10, 2, 31]; // 錯(cuò)誤:返回布爾值,排序結(jié)果不可靠 numArr.sort((a, b) => a > b); // 正確:返回?cái)?shù)字,排序結(jié)果穩(wěn)定 numArr.sort((a, b) => a - b);
4. 誤區(qū)4:中文排序直接使用字符串比較
直接用 a > b 比較中文,會(huì)按 Unicode 編碼排序,不符合中文的拼音/筆畫排序邏輯,應(yīng)使用 localeCompare() 并指定中文環(huán)境。
正確示例:中文拼音排序
const chineseArr = ["張三", "李四", "王五", "趙六"];
// localeCompare("zh-CN"):按中文拼音排序
chineseArr.sort((a, b) => a.localeCompare(b, "zh-CN"));
console.log(chineseArr); // ["李四", "王五", "張三", "趙六"]
六、sort()方法的性能說(shuō)明
sort() 的底層排序算法并非固定(由瀏覽器內(nèi)核實(shí)現(xiàn)):
- Chrome/V8 引擎:對(duì)于小型數(shù)組(長(zhǎng)度≤22)使用「插入排序」,大型數(shù)組使用「快速排序的變種(TimSort/QuickSort)」,平均時(shí)間復(fù)雜度為
O(n log n)。 - Firefox 引擎:使用「歸并排序」,時(shí)間復(fù)雜度
O(n log n)。
日常開(kāi)發(fā)中無(wú)需關(guān)注底層實(shí)現(xiàn),只需關(guān)注排序規(guī)則和穩(wěn)定性即可,其性能足以滿足絕大多數(shù)業(yè)務(wù)場(chǎng)景。
總結(jié)
sort()是原地排序方法,會(huì)修改原始數(shù)組,需保留原數(shù)組時(shí)應(yīng)先拷貝([...arr]/arr.slice())。- 默認(rèn)按字符串 Unicode 排序,數(shù)字/對(duì)象排序必須傳入比較函數(shù),核心規(guī)則是「返回負(fù)數(shù)a在前、返回正數(shù)a在后、返回0位置不變」。
- 常見(jiàn)場(chǎng)景:數(shù)字正/降序(
a-b/b-a)、對(duì)象多條件排序、中文排序(localeCompare("zh-CN"))。 - ES6 及以后
sort()是穩(wěn)定排序,特殊值(undefined)默認(rèn)排末尾,使用時(shí)需規(guī)避非數(shù)字返回值等誤區(qū)。
到此這篇關(guān)于js Array sort實(shí)戰(zhàn)排序全面講解教程的文章就介紹到這了,更多相關(guān)js Array sort排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用js實(shí)現(xiàn)每隔一秒刷新時(shí)間的實(shí)例(含年月日時(shí)分秒)
下面小編就為大家?guī)?lái)一篇用js實(shí)現(xiàn)每隔一秒刷新時(shí)間的實(shí)例(含年月日時(shí)分秒)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
基于canvas實(shí)現(xiàn)的絢麗圓圈效果完整實(shí)例
這篇文章主要介紹了基于canvas實(shí)現(xiàn)的絢麗圓圈效果,以完整實(shí)例形式分析了JavaScript結(jié)合html5的canvas實(shí)現(xiàn)動(dòng)態(tài)圖形的繪制技巧,需要的朋友可以參考下2016-01-01
JS實(shí)現(xiàn)漂亮的時(shí)間選擇框效果
這篇文章主要介紹了JS實(shí)現(xiàn)漂亮的時(shí)間選擇框效果,結(jié)合實(shí)例形式分析了javascript時(shí)間選擇框插件的實(shí)現(xiàn)與使用方法,需要的朋友可以參考下2016-08-08
如何去除js中的json存在的轉(zhuǎn)義字符\問(wèn)題
這篇文章主要介紹了如何去除js中的json存在的轉(zhuǎn)義字符\問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
JS操作xml對(duì)象轉(zhuǎn)換為Json對(duì)象示例
本篇文章主要介紹了JS操作xml對(duì)象轉(zhuǎn)換為Json對(duì)象示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03
使用hasOwnProperty時(shí)報(bào)錯(cuò)的解決方法
hasOwnProperty這個(gè)方法是用來(lái)查找一個(gè)對(duì)象是否有某個(gè)屬性,且查找的屬性必須是對(duì)象本身的一個(gè)成員,但是不會(huì)去查找對(duì)象的原型鏈,文中介紹了使用示例代碼及使用時(shí)可能會(huì)遇到的問(wèn)題,對(duì)hasOwnProperty報(bào)錯(cuò)原因分析及解決方法感興趣的朋友一起看看吧2024-01-01
JavaScript讀寫二進(jìn)制數(shù)據(jù)的方法詳解
avascript里有兩個(gè)內(nèi)置對(duì)象,一個(gè)是ArrayBuffer;一個(gè)是DataView,讀寫二進(jìn)制數(shù)據(jù)都需要使用這兩個(gè)對(duì)象。這篇文章主要給大家介紹了關(guān)于JavaScript讀寫二進(jìn)制數(shù)據(jù)的方法,需要的朋友可以參考下2018-09-09
JS獲取屏幕高度的簡(jiǎn)單實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇JS獲取屏幕高度的實(shí)現(xiàn)代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05

