!轉(zhuǎn)載鏈接:https://www.w3cplus.com/javascript/array-part-4.html
??!僅供學(xué)習(xí),若有侵權(quán),立刻刪除?。?/p>
在實(shí)際的業(yè)務(wù)當(dāng)中,很多時(shí)候要對(duì)定義好的數(shù)組重新排序。在 JavaScript 中自帶了兩個(gè)方法,可以對(duì)數(shù)組進(jìn)行排序操作。這兩個(gè)方法就是sort()和reverse()。今天就來學(xué)習(xí)這兩個(gè)方法相關(guān)的知識(shí)。
sort()方法
sort()方法對(duì)數(shù)組的元素做原地的排序,并返回這個(gè)數(shù)組。默認(rèn)情況下,sort()方法是按升序排列數(shù)組項(xiàng)。即最小的值位于最前面,最大的值排列在最后面。為了實(shí)現(xiàn)排序,sort()方法會(huì)調(diào)用每個(gè)數(shù)組項(xiàng)的toString()轉(zhuǎn)型方法,然后比較得到的字符串,以確定如何排序。
先來看一個(gè)簡單的示例:
<pre class="hljs ruby">var arr = ['hello','jame','Jack','dog']; // 定義一個(gè)數(shù)組
console.log(arr.sort()); // ["Jack", "dog", "hello", "jame"]</pre>
正如前面所言,sort()方法未調(diào)用任何參數(shù)時(shí),是按升序排列的,也就是按字母的順序排列,所以我們看到結(jié)果也是正確的。
接下來,再看一個(gè)數(shù)字的數(shù)組排列的示例:
<pre class="hljs javascript">var arr = [1,5,10,22]; // 定義一個(gè)數(shù)組
console.log(arr.sort()); // [1, 10, 22, 5]</pre>
可見,即使示例中數(shù)組的順序沒有任何問題,但sort()方法對(duì)數(shù)組進(jìn)行重新排序操作之后,順序反而不對(duì)了。這究竟是為何呢?
查了相關(guān)文檔才知道,sort()方法:如果省略參數(shù),數(shù)組項(xiàng)會(huì)先根據(jù)toString()函數(shù)將其值轉(zhuǎn)換成字符串在進(jìn)行比較,是按 UNICODE 進(jìn)行比較的,然后根據(jù)這個(gè)進(jìn)行排序。正如最前面的示例,"Jack" 會(huì)排在 "dog" 前面。當(dāng)數(shù)字進(jìn)行排序的時(shí)候,"5" 會(huì)出現(xiàn)在 "10" 和 "22" 之后,因?yàn)樗麄兿葧?huì)被轉(zhuǎn)換為字符串,而 “10” 和“22”都比 “5” 要靠前。
我們可以使用charCodeAt()來驗(yàn)證一下:
<pre class="hljs coffeescript">"Jack".charCodeAt() ==> 74
"dog".charCodeAt() ==> 100
"5".charCodeAt() ==> 53
"10".charCodeAt() ==> 49
"22".charCodeAt() ==> 50</pre>
如此一來,這不是最佳方案。幸好,sort()方法可以接受一個(gè)比較函數(shù)compareFunction作為參數(shù),以便我們指定哪個(gè)值位于哪個(gè)值的前面。
如果指明了compareFunction,那么數(shù)組會(huì)按照調(diào)用該函數(shù)的返回值進(jìn)行排序。比較函數(shù)compareFunction接收兩個(gè)參數(shù)a和b,a和b是兩個(gè)將要被比較的元素:
-
compareFunction(a,b)返回的值小于0:那么a就小于b,也就是說a排在了b的前面 -
compareFunction(a,b)返回的值大于0: 那么a就大于b,也就是說a排在了b的后面 -
compareFunction(a,b)返回的值等于0:那么a就等于b,也就是說a和b的位置保持不變
compareFunction(a,b)函數(shù):
<pre class="hljs javascript">function compareFunction (a, b) {
if (a < b) {
return -1; // a排在b的前面
} else if (a > b) {
return 1; // a排在b的后面
} else {
return 0; // a和b的位置保持不變
}
}</pre>
這個(gè)函數(shù)可適用于大多數(shù)數(shù)據(jù)類型,只要將compareFunction(a,b)函數(shù)作為參數(shù)傳給sort()方法即可。因到前面的示例:
<pre class="hljs javascript">var arr = [1,5,10,22]; // 定義一個(gè)數(shù)組
arr.sort(compareFunction); // 將compareFunction函數(shù)作為參數(shù)傳給 sort()
console.log(arr); // [1, 5, 10, 22]</pre>
數(shù)組arr仍然保持了正確的升序排列。其實(shí)可以通過compareFunction(a,b)對(duì)數(shù)組作降序排列,只需要將compareFunction函數(shù)的返回值做個(gè)調(diào)整即可:
<pre class="hljs javascript">function compareFunction (a, b){
if (a < b) {
return 1; // a排在b的后面
} else if (a > b) {
return -1; // a排在b的前面
} else {
return 0; // a 和 b 保持位置不變
}
}
var arr = [1, 5, 10, 22]; //定義一個(gè)數(shù)組
arr.sort(compareFunction); // 將compareFunction函數(shù)作為參數(shù)傳給sort()
console.log(arr); // [22, 10, 5, 1]</pre>
注:compareFunction(a, b) 必須總是對(duì)相同的輸入返回相同的比較結(jié)果,否則排序的結(jié)果將是不確定的。
上面也說到了,sort()方法傳入compareFunction(a,b)參數(shù)時(shí),返回的值可能有3個(gè),所以下面這樣的寫法是錯(cuò)誤的:
<pre class="hljs javascript">function compareFunction (a, b) {
return a < b;
}
var arr = [21, 0, 3, 11, 4, 5, 6, 7, 8, 9, 10];
arr.sort(compareFunction);
console.log(arr); // [5, 21, 11, 10, 9, 8, 7, 6, 4, 3, 0]</pre>
可能得的結(jié)果是 [5, 21, 11, 10, 9, 8, 7, 6, 4, 3, 0],這并不是正確的結(jié)果,那是因?yàn)?code>return a < b只返回了兩種值 true或false,相當(dāng)于1或0,而沒有-1。
對(duì)于數(shù)字類型或valueOf()方法返回?cái)?shù)值類型的對(duì)象類型,可以使用一個(gè)更簡單的比較函數(shù)。
<pre class="hljs javascript">// ascSort(a,b)傳給sort(),數(shù)字?jǐn)?shù)組作升序排列
function ascSort (a, b) { // a和b是數(shù)組中相鄰的兩個(gè)數(shù)組項(xiàng)
return a - b;
// 如果 return -1, 表示a小于b,a排列在b的前面
// 如果 return 1, 表示a大于b,a排列在b的后面
// 如果 return 0, 表示a等于b,a和b的位置保持不變
}
// desSort(a,b)傳給sort(),數(shù)字?jǐn)?shù)組作降序排列
function desSort (a, b) { // a和b是數(shù)組中相鄰的兩個(gè)數(shù)組項(xiàng)
return b - a;
// 如果 return -1, 表示b小于a,b排列在a的前面
// 如果 return 1, 表示b大于a, b排列在a的后面
// 如果 return 0, 表示 b等于a, b和a的位置保持不變
}</pre>
來看看結(jié)果是不是我們想要的結(jié)果:
<pre class="hljs javascript">var arr = [1,4,10,3],
arr2 = [100,12,99,3,2]; //定義數(shù)組
arr.sort(ascSort); // 將ascSort函數(shù)傳給sort()
arr2.sort(desSort); // 將desSort函數(shù)傳給sort()
console.log(arr); // [1, 3, 4, 10]
console.log(arr2); // [100, 99, 12, 3, 2]</pre>
字符數(shù)組排列
創(chuàng)建一個(gè)字符串?dāng)?shù)組,并且使用sort()對(duì)字符串進(jìn)行重新排序:
<pre class="hljs javascript">var stringArray = ['blue', 'Humpback', 'Beluga'];
stringArray.sort();
console.log('字符串?dāng)?shù)組stringArray:' + stringArray);</pre>
Chrome 輸出的結(jié)果:
<pre class="hljs css">字符串?dāng)?shù)組stringArray:Beluga,Humpback,blue</pre>
數(shù)字字符串?dāng)?shù)組排列
創(chuàng)建一個(gè)數(shù)字字符串?dāng)?shù)組之后對(duì)數(shù)組進(jìn)行排序,對(duì)比數(shù)字?jǐn)?shù)組分別指定與不指定比較函數(shù)的結(jié)果:
<pre class="hljs javascript">var numericStringArray = ['80', '9', '700'];
function compareFunction (a, b) {
return a - b;
}
console.log('不指定比較函數(shù)的數(shù)字字符串?dāng)?shù)組排列:' + numericStringArray.sort());
console.log('指定比較函數(shù)的數(shù)字字符串?dāng)?shù)組排列:' + numericStringArray.sort(compareFunction));</pre>
Chrome 輸出的結(jié)果:
<pre class="hljs">不指定比較函數(shù)的數(shù)字字符串?dāng)?shù)組排列:700,80,9
指定比較函數(shù)的數(shù)字字符串?dāng)?shù)組排列:9,80,700</pre>
數(shù)字?jǐn)?shù)組排列
創(chuàng)建一個(gè)數(shù)字?jǐn)?shù)組之后對(duì)數(shù)組進(jìn)行排序,對(duì)比數(shù)字?jǐn)?shù)組分別指定與不指定比較函數(shù)的結(jié)果:
<pre class="hljs javascript">var numberArray = [80, 9, 700];
function compareFunction (a, b) {
return a - b;
}
console.log('不指定比較函數(shù)的數(shù)字?jǐn)?shù)組排列:' + numberArray.sort());
console.log('指定比較函數(shù)的數(shù)字?jǐn)?shù)組排列:' + numberArray.sort(compareFunction));</pre>
Chrome 輸出的結(jié)果:
<pre class="hljs">不指定比較函數(shù)的數(shù)字字符串?dāng)?shù)組排列:700,80,9
指定比較函數(shù)的數(shù)字字符串?dāng)?shù)組排列:9,80,700</pre>
數(shù)字和數(shù)字字符串混合數(shù)組排列
創(chuàng)建一個(gè)數(shù)字和數(shù)字字符串混合數(shù)組之后進(jìn)行排序,對(duì)比數(shù)組分別指定與不指定比較函數(shù)的結(jié)果:
<pre class="hljs javascript">var mixedNumericArray = ['80', '9', '700', 40, 1, 5, 200];
function compareFunction (a, b){
return a - b;
}
console.log('不指定比較函數(shù)的數(shù)組排列:' + mixedNumericArray.sort());
console.log('指定比較函數(shù)的數(shù)組排列' + mixedNumericArray.sort(compareFunction));</pre>
Chrome 輸出的結(jié)果:
<pre class="hljs">不指定比較函數(shù)的數(shù)組排列:1,200,40,5,700,80,9
指定比較函數(shù)的數(shù)組排列1,5,9,40,80,200,700</pre>
數(shù)字?jǐn)?shù)組隨機(jī)排列
除了給數(shù)字?jǐn)?shù)組進(jìn)行升序或降序排列之外,還可以定義一個(gè)隨機(jī)函數(shù),實(shí)現(xiàn)數(shù)組的隨機(jī)排列。定義的隨機(jī)函數(shù)返回正數(shù)或者負(fù)數(shù),并表將隨機(jī)函數(shù)傳給sort()方法,此時(shí)sort()方法根據(jù)隨機(jī)函數(shù)返回的正負(fù)數(shù)來決定兩個(gè)值之前的位置。
<pre class="hljs javascript">var randomArray = [9,0,23,8,3,5];
function randomSort(a, b) {
return Math.random() - 0.5;
}
console.log(randomArray.sort(randomSort));
// [8, 5, 9, 0, 23, 3]
// [8, 3, 5, 0, 23, 9]
// [8, 5, 0, 3, 9, 23]</pre>
對(duì)象數(shù)組排列
對(duì)于對(duì)象數(shù)組排列,我們同樣需要先寫一個(gè)構(gòu)造函數(shù):
<pre class="hljs javascript">function objectSort(property, desc) {
//降序排列
if (desc) {
return function (a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
}
return function (a, b) {
return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
}
}
var myArray = [
{ "name": "John Doe", "age": 29 },
{ "name": "Anna Smith", "age": 24 },
{ "name": "Peter Jones", "age": 39 }
]
console.log(myArray.sort(objectSort('name',true))); // 按object中的name的降序排列</pre>
來看看 Chrome 輸出的前后結(jié)果:

另外,只需要改變比較函數(shù)objectSort()中的desc參數(shù)值為flase,數(shù)組就會(huì)按object指定的property屬性降序排列:
<pre class="hljs javascript">console.log(myArray.sort(objectSort('age',false))); //按objcet中的age升序排列</pre>
Chrome 輸出的前后結(jié)果:

除此之外,還有其的對(duì)比較函數(shù),如下所示:
<pre class="hljs javascript">function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
console.log(myArray.sort(dynamicSort('age'))); // 按升序排列
console.log(myArray.sort(dynamicSort('-age'))); // 按降序排列</pre>
上面介紹的是按一個(gè)屬性進(jìn)行排序,但很多時(shí)候,希望按多個(gè)屬性排序,那么比較函數(shù)需要做一定的調(diào)整:
<pre class="hljs javascript">function dynamicSortMultiple() {
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
myArray.sort(dynamicSortMultiple('name','-age'));</pre>
reverse()方法
reverse()方法相對(duì)而言要簡單得多,它就是用來顛倒數(shù)組中元素的位置,并返回該數(shù)組的引用。比如我們有一個(gè)數(shù)組:
<pre class="hljs coffeescript">var myArray = ["Airen","W3cplus","Blog"];
console.log(myArray.reverse()); // ["Blog", "W3cplus", "Airen"]</pre>
總結(jié)
本文主要介紹了數(shù)組中元素項(xiàng)的排序方法。而主要詳細(xì)介紹的是sort()方法。通過給sort()方法傳遞不同的比較函數(shù),我們可以實(shí)現(xiàn)字符串?dāng)?shù)組、數(shù)字?jǐn)?shù)組、數(shù)字和數(shù)字字符串混合數(shù)組、對(duì)象數(shù)組等按順序 (升序或降序) 排列。