如何在JavaScript中對對象數(shù)組進行排序
如果需要按特定順序?qū)ο髷?shù)組進行排序,我們很有可能會直接找個 JS 庫來用。其實大可不必,JS 原生中的 Array.sort就能直接一些復雜又漂亮的排序。
本文中,將介紹一些 Array.sort 的常規(guī)排序和一些騷操作。
基本數(shù)組排序
默認情況下,Array.sort函數(shù)將數(shù)組中需要排序的每個元素轉(zhuǎn)換為字符串,并按 Unicode 順序?qū)ζ溥M行比較。
- const foo = [9, 1, 4, 'zebroid', 'afterdeck'];
 - foo.sort(); // returns [ 1, 4, 9, 'afterdeck', 'zebroid' ]
 - const bar = [5, 18, 32, new Set, { user: 'Eleanor Roosevelt' }];
 - bar.sort(); // returns [ 18, 32, 5, { user: 'Eleanor Roosevelt' }, Set {} ]
 
你可能會好奇為啥32排在5之前。發(fā)生這種情況是因為數(shù)組中的每個元素都首先轉(zhuǎn)換為字符串,并且按照Unicode順序,"32"在"5"之前。
需要注意的是,Array.sort會更改原數(shù)組。
- const baz = ['My cat ate my homework', 37, 9, 5, 17];
 - baz.sort(); // baz數(shù)組被修改
 - console.log(baz); // shows [ 17, 37, 5, 9, 'My cat ate my homework' ]
 
為避免這種情況,我們可以創(chuàng)建要排序的數(shù)組的新實例,然后在新的數(shù)組上進行修改。這里可以使用 Array.slice它返回是一個新的數(shù)組實例。
- // 創(chuàng)建baz數(shù)組的新實例并對其進行排序
 - const sortedBaz = baz.slice().sort();
 
我們還可以使用 ES6 中的展開運算符來做:
- const sortedBaz = [...baz].sort();
 
在兩種情況下,輸出是相同的:
- console.log(baz); // ['My cat ate my homework', 37, 9, 5, 17];
 - console.log(sortedBaz); // [ 17, 37, 5, 9, 'My cat ate my homework' ]
 
單獨使用Array.sort不能對對象數(shù)組進行排序。但不必擔心,sort 的還提供一個參數(shù),該參數(shù)使數(shù)組元素根據(jù)compare函數(shù)的返回值進行排序。
使用比較函數(shù)進行排序
假設foo和bar是compare函數(shù)要比較的兩個元素,compare函數(shù)的返回值設置如下:
- 小于0:foo在bar之前
 - 大于0 :bar在foo之前
 - 等于0:foo和bar彼此保持不變。
 
來看一個簡單的示例:
- const nums = [79, 48, 12, 4];
 - function compare(a, b) {
 - if (a > b) return 1;
 - if (b > a) return -1;
 - return 0;
 - }
 - nums.sort(compare);
 - // => 4, 12, 48, 79
 
我們可以稍微重構(gòu)一下:
- function compare(a, b) {
 - return a - b;
 - }
 
使用在使用箭頭函數(shù)進行重構(gòu):
- nums.sort((a, b) => a - b);
 
如何對對象數(shù)組進行排序
現(xiàn)在,我們來按一下對對象數(shù)組的排序。假設有下面的 singers 數(shù)組:
- const singers = [
 - { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
 - { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
 - { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
 - { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
 - ];
 
我們可以使用 compare函數(shù),然后根據(jù) singers 中的 band 字段來進行排序。
- function compare(a, b) {
 - // 使用 toUpperCase() 忽略字符大小寫
 - const bandA = a.band.toUpperCase();
 - const bandB = b.band.toUpperCase();
 - let comparison = 0;
 - if (bandA > bandB) {
 - comparison = 1;
 - } else if (bandA < bandB) {
 - comparison = -1;
 - }
 - return comparison;
 - }
 - singers.sort(compare);
 - /* returns [
 - { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
 - { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
 - { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
 - { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 }
 - ] */
 
如果要讓上面的順序相反,可以這么做:
- function compare(a, b) {
 - ...
 - // 乘以-1來反轉(zhuǎn)返回值
 - return comparison * -1;
 - }
 
創(chuàng)建一個動態(tài)排序函數(shù)
最后,排序函數(shù)更具動態(tài)性。
我們創(chuàng)建一個排序函數(shù),可以使用該函數(shù)對一組對象進行排序,這些對象的值可以是字符串或數(shù)字。該函數(shù)有兩個參數(shù)-我們要排序的鍵和返回結(jié)果的順序(即升序或降序):
- const singers = [
 - { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
 - { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
 - { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
 - { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
 - ];
 - function compareValues(key, order = 'asc') {
 - return function innerSort(a, b) {
 - if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
 - // 該屬性在其中一個對象上不存在
 - return 0;
 - }
 - const varA = (typeof a[key] === 'string')
 - ? a[key].toUpperCase() : a[key];
 - const varB = (typeof b[key] === 'string')
 - ? b[key].toUpperCase() : b[key];
 - let comparison = 0;
 - if (varA > varB) {
 - comparison = 1;
 - } else if (varA < varB) {
 - comparison = -1;
 - }
 - return (
 - (order === 'desc') ? (comparison * -1) : comparison
 - );
 - };
 - }
 
使用:
- //數(shù)組按`band`排序,默認為升序
 - singers.sort(compareValues('band'));
 - // 數(shù)組按 `band` 降序排序
 - singers.sort(compareValues('band', 'desc'));
 - // 數(shù)組按 `name` 升序排序
 - singers.sort(compareValues('name'));
 - // 數(shù) 組born 降序排序
 - singers.sort(compareValues('born', 'desc'));
 
在上面的代碼中,hasOwnProperty方法用于檢查指定的屬性是否在每個對象上定義,且沒有通過原型鏈繼承。如果沒有在兩個對象上定義,函數(shù)返回0,排序順序保持不變(即對象之間保持不變)。
typeof運算符還用于檢查屬性值的數(shù)據(jù)類型,這使函數(shù)可以確定對數(shù)組進行排序的正確方法。如果指定屬性的值是一個字符串,則使用toUpperCase方法將其所有字符都轉(zhuǎn)換為大寫,因此排序時將忽略字符大小寫
最后,你可以根據(jù)自己需求來調(diào)整上面的函數(shù)。
String.prototype.localeCompare()
在上面的示例中,我們希望能夠?qū)ο髷?shù)組進行排序,其值可以是字符串或數(shù)字。但是,如果我們知道處理值是字符串的對象,則可以使用 JS 的localeCompare方法
比較兩個字符串,并返回下列值中的一個:
- 如果 字符串 在 字母 表中 應該 排在 字符串 參數(shù) 之前, 則 返回 一個 負數(shù);
 - 如果 字符串 等于 字符串 參數(shù), 則 返回 0;
 - 字符串 在 字母 表中 應該 排在 字符串 參數(shù) 之后, 則 返回 一個 正數(shù);
 
- ['bjork', 'Bjork', 'Björk'].sort();
 - // [ 'Bjork', 'Björk', 'bjork' ]
 - ['bjork', 'Bjork', 'Björk'].sort((a, b) => a.localeCompare(b));
 - // [ 'bjork', 'Bjork', 'Björk' ]
 
根據(jù)compareValues函數(shù),我們可以這么寫:
- function compareValues(key, order = 'asc') {
 - return function innerSort(a, b) {
 - if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) return 0;
 - const comparison = a[key].localeCompare(b[key]);
 - return (
 - (order === 'desc') ? (comparison * -1) : comparison
 - );
 - };
 - }
 
總結(jié)
上面就是使用普通JS 函數(shù)對對象數(shù)組排序的簡短的介紹。盡管許多庫都提供了這種動態(tài)排序能力,但我們自己實現(xiàn)這個方法其實也不信。另外,了解幕后發(fā)生了對我們來說并沒有壞處。
今天就跟大家分享到這里了,感謝大家的觀看,我們下期再見。
作者:James Hibbard 譯者:前端小智 來源:sitepoint
原文:https://www.sitepoint.com/sort-an-array-of-objects-in-javascript/
本文轉(zhuǎn)載自微信公眾號「大遷世界」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系大遷世界公眾號。
















 
 
 






 
 
 
 