Javascript一維數(shù)組和對(duì)象數(shù)組排序方案
作者:Wonfody
來源:SegmentFault 思否
一、普通一維數(shù)組
js中用 sort()?方法為數(shù)組排序。sort()?方法有一個(gè)可選參數(shù),是用來確定元素順序的函數(shù)。如果這個(gè)參數(shù)被省略,那么數(shù)組中的元素將按照ASCII字符順序進(jìn)行排序。如:
var arr = ["a", "A", "c", "B"];arr.sort();console.log(arr); // ["A", "B", "a", "c"]
注意:sort()?方法在在原數(shù)組上進(jìn)行排序,不生成副本。
因?yàn)樽帜窤、B的ASCII值分別為65、66,而a、b的值分別為97、99,所以上面輸出的結(jié)果是?["A", "B", "a", "c"]?。
如果數(shù)組元素是數(shù)字呢,結(jié)果會(huì)是怎樣?
var arr = [15, 8, 25, 3];arr.sort();console.log(arr); // [15, 25, 3, 8]
結(jié)果是?[15, 25, 3, 8]?。其實(shí),sort方法會(huì)調(diào)用每個(gè)元素的 toString()?方法,得到字符串,然后再對(duì)得到的字符串進(jìn)行排序。雖然數(shù)值15比3大,但在進(jìn)行字符串比較時(shí)"15"則排在"3"前面。顯然,這種結(jié)果不是我們想要的,這時(shí),sort()?方法的參數(shù)就起到了作用,我們把這個(gè)參數(shù)叫做比較函數(shù)。
比較函數(shù)接收兩個(gè)參數(shù),如果第一個(gè)參數(shù)應(yīng)該位于第二個(gè)之前則返回一個(gè)負(fù)數(shù),如果第一個(gè)參數(shù)應(yīng)該位于第二個(gè)之后則返回一個(gè)正數(shù),如果兩個(gè)參數(shù)相等則返回0。例子:
var arr = [23, 9, 4, 78, 3];// 比較函數(shù)var compare = function (x, y) {if (x < y) {return -1;} else if (x > y) {return 1;} else {return 0;}}console.log(arr.sort(compare));
結(jié)果為?[3, 4, 9, 23, 78]?,返回了我們想要的結(jié)果。如果要按降序排序,比較函數(shù)寫成這樣即可:
var compare = function (x, y) {if (x < y) {return 1;} else if (x > y) {return -1;} else {return 0;}}
我們并不能用比較函數(shù)比較一個(gè)不能轉(zhuǎn)化為數(shù)字的字符串與數(shù)字的順序:
var arr = ["b", 5];console.log(arr.sort(compare))
結(jié)果是?["b", 5]?。因?yàn)楸容^函數(shù)在比較時(shí),會(huì)把先把字符串轉(zhuǎn)化為數(shù)字,然后再比較,字符串b不能轉(zhuǎn)化為數(shù)字,所以就不能比較大小。然而,當(dāng)不用比較函數(shù)時(shí),會(huì)比較ASCII值,所以結(jié)果是?[5, "b"]?。
二、數(shù)組對(duì)象
如果數(shù)組項(xiàng)是對(duì)象,我們需要根據(jù)數(shù)組項(xiàng)的某個(gè)屬性對(duì)數(shù)組進(jìn)行排序,要怎么辦呢?其實(shí)和前面的比較函數(shù)也差不多:
var arr = [{name: "zlw", age: 24}, {name: "wlz", age: 25}];var compare = function (obj1, obj2) {var val1 = obj1.name;var val2 = obj2.name;if (val1 < val2) {return -1;} else if (val1 > val2) {return 1;} else {return 0;}}console.log(arr.sort(compare));
輸出結(jié)果為?[{ name="wlz", age=25}, { name="zlw", age=24}]?,可以看到數(shù)組已經(jīng)按照 name 屬性進(jìn)行了排序。我們可以對(duì)上面的比較函數(shù)再改造一下:
var compare = function (prop) {return function (obj1, obj2) {var val1 = obj1[prop];var val2 = obj2[prop];if (val1 < val2) {return -1;} else if (val1 > val2) {return 1;} else {return 0;}}}
如果想按照 age 進(jìn)行排序,arr.sort(compare("age"))?即可。
但是對(duì)age屬性進(jìn)行排序時(shí)需要注意了,如果age屬性的值是數(shù)字,那么排序結(jié)果會(huì)是我們想要的。但很多時(shí)候我們從服務(wù)器傳回來的數(shù)據(jù)中,屬性值通常是字符串。現(xiàn)在我把上面的數(shù)組改為:
var arr = [{name: "zlw", age: "24"}, {name: "wlz", age: "5"}];可以看到,我把 age 屬性由數(shù)字改為了字符串,第二個(gè)數(shù)組項(xiàng)的 age 值改為了?"5"?。再次調(diào)用 arr.sort(compare("age"))?后,結(jié)果為:
[Object?{?name="zlw",?age="24"},?Object?{?name="wlz",?age="5"}]我們的期望是5排在24前面,但是結(jié)果不是。這是因?yàn)楫?dāng)兩個(gè)數(shù)字字符串比較大小時(shí),會(huì)比較它們的ASCII值大小,比較規(guī)則是:從第一個(gè)字符開始,順次向后直到出現(xiàn)不同的字符為止,然后以第一個(gè)不同的字符的ASCII值確定大小。所以"24"與"5"比較大小時(shí),先比較”2“與"5"的ASCII值,顯然”2“的ASCII值比"5"小,即確定排序順序。
現(xiàn)在,我們需要對(duì)比較函數(shù)再做一些修改:
var compare = function (prop) {return function (obj1, obj2) {var val1 = obj1[prop];var val2 = obj2[prop];if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {val1 = Number(val1);val2 = Number(val2);}if (val1 < val2) {return -1;} else if (val1 > val2) {return 1;} else {return 0;}}}
在比較函數(shù)中,先把比較屬性值轉(zhuǎn)化為數(shù)字 Number(val1)?再通過 !isNaN(Number(val1))?判斷轉(zhuǎn)化后的值是不是數(shù)字(有可能是NaN),轉(zhuǎn)化后的值如果是數(shù)字,則比較轉(zhuǎn)換后的值,這樣就可以得到我們想要的結(jié)果了, 調(diào)用 arr.sort(compare("age"))?得到:
[Object { name="wlz", age="5"}, Object { name="zlw", age="24"}]可以看到,確實(shí)是按正確的方式排序了。
參考:
https://www.cnblogs.com/xljzlw/p/3694861.html


