1. 程式人生 > >JavaScript學習筆記:數組的sort()和reverse()方法

JavaScript學習筆記:數組的sort()和reverse()方法

content 參數 n) strong true 知識 efi 調整 數字

在實際的業務當中,很多時候要對定義好的數組重新排序。在JavaScript中自帶了兩個方法,可以對數組進行排序操作。這兩個方法就是sort()reverse()。今天就來學習這兩個方法相關的知識。

sort()方法

sort()方法對數組的元素做原地的排序,並返回這個數組。默認情況下,sort()方法是按升序排列數組項。即最小的值位於最前面,最大的值排列在最後面。為了實現排序,sort()方法會調用每個數組項的toString()轉型方法,然後比較得到的字符串,以確定如何排序。

先來看一個簡單的示例:

var arr = [‘hello‘,‘jame‘,‘Jack‘,‘dog‘]; // 定義一個數組
console.log(arr.sort()); // ["Jack", "dog", "hello", "jame"]

正如前面所言,sort()方法未調用任何參數時,是按升序排列的,也就是按字母的順序排列,所以我們看到結果也是正確的。

接下來,再看一個數字的數組排列的示例:

var arr = [1,5,10,22]; // 定義一個數組
console.log(arr.sort()); // [1, 10, 22, 5]

可見,即使示例中數組的順序沒有任何問題,但sort()方法對數組進行重新排序操作之後,順序反而不對了。這究竟是為何呢?

查了相關文檔才知道,sort()方法:如果省略參數,數組項會先根據toString()函數將其值轉換成字符串在進行比較,是按UNICODE進行比較的,然後根據這個進行排序。

正如最前面的示例,"Jack"會排在"dog"前面。當數字進行排序的時候,"5"會出現在"10"和"22"之後,因為他們先會被轉換為字符串,而“10”和“22”都比“5”要靠前。

我們可以使用charCodeAt()來驗證一下:

"Jack".charCodeAt() ==> 74
"dog".charCodeAt()  ==> 100
"5".charCodeAt()    ==> 53
"10".charCodeAt()   ==> 49
"22".charCodeAt()   ==> 50

如此一來,這不是最佳方案。幸好,sort()方法可以接受一個比較函數compareFunction作為參數,以便我們指定哪個值位於哪個值的前面。

如果指明了compareFunction,那麽數組會按照調用該函數的返回值進行排序。比較函數compareFunction接收兩個參數abab是兩個將要被比較的元素:

  • compareFunction(a,b)返回的值小於0:那麽a就小於b,也就是說a排在了b的前面
  • compareFunction(a,b)返回的值大於0: 那麽a就大於b,也就是說a排在了b的後面
  • compareFunction(a,b)返回的值等於0:那麽a就等於b,也就是說ab的位置保持不變

compareFunction(a,b)函數:

function compareFunction (a, b) {
    if (a < b) {
        return -1; // a排在b的前面
    } else if (a > b) {
        return 1; // a排在b的後面
    } else {
        return 0; // a和b的位置保持不變
    }
}

這個函數可適用於大多數數據類型,只要將compareFunction(a,b)函數作為參數傳給sort()方法即可。因到前面的示例:

var arr = [1,5,10,22]; // 定義一個數組
arr.sort(compareFunction); // 將compareFunction函數作為參數傳給 sort()
console.log(arr); // [1, 5, 10, 22]

數組arr仍然保持了正確的升序排列。其實可以通過compareFunction(a,b)對數組作降序排列,只需要將compareFunction函數的返回值做個調整即可:

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]; //定義一個數組
arr.sort(compareFunction); // 將compareFunction函數作為參數傳給sort()
console.log(arr); // [22, 10, 5, 1]

註:compareFunction(a, b) 必須總是對相同的輸入返回相同的比較結果,否則排序的結果將是不確定的。

上面也說到了,sort()方法傳入compareFunction(a,b)參數時,返回的值可能有3個,所以下面這樣的寫法是錯誤的:

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]

可能得的結果是 [5, 21, 11, 10, 9, 8, 7, 6, 4, 3, 0],這並不是正確的結果,那是因為return a < b只返回了兩種值 truefalse,相當於10,而沒有-1

對於數字類型或valueOf()方法返回數值類型的對象類型,可以使用一個更簡單的比較函數。

// ascSort(a,b)傳給sort(),數字數組作升序排列
function ascSort (a, b) {  // a和b是數組中相鄰的兩個數組項
    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(),數字數組作降序排列
function desSort (a, b) { // a和b是數組中相鄰的兩個數組項
    return b - a;
    // 如果 return -1, 表示b小於a,b排列在a的前面
    // 如果 return 1, 表示b大於a, b排列在a的後面
    // 如果 return 0, 表示 b等於a, b和a的位置保持不變
}

來看看結果是不是我們想要的結果:

var arr = [1,4,10,3], 
    arr2 = [100,12,99,3,2]; //定義數組
arr.sort(ascSort); // 將ascSort函數傳給sort()
arr2.sort(desSort); // 將desSort函數傳給sort()
console.log(arr); // [1, 3, 4, 10]
console.log(arr2); // [100, 99, 12, 3, 2]

字符數組排列

創建一個字符串數組,並且使用sort()對字符串進行重新排序:

var stringArray = [‘blue‘, ‘Humpback‘, ‘Beluga‘];
stringArray.sort();
console.log(‘字符串數組stringArray:‘ + stringArray);

Chrome輸出的結果:

字符串數組stringArray:Beluga,Humpback,blue

數字字符串數組排列

創建一個數字字符串數組之後對數組進行排序,對比數字數組分別指定與不指定比較函數的結果:

var numericStringArray = [‘80‘, ‘9‘, ‘700‘];

function compareFunction (a, b) {
    return a - b;
}

console.log(‘不指定比較函數的數字字符串數組排列:‘ + numericStringArray.sort());
console.log(‘指定比較函數的數字字符串數組排列:‘ + numericStringArray.sort(compareFunction));

Chrome輸出的結果:

不指定比較函數的數字字符串數組排列:700,80,9
指定比較函數的數字字符串數組排列:9,80,700

數字數組排列

創建一個數字數組之後對數組進行排序,對比數字數組分別指定與不指定比較函數的結果:

var numberArray = [80, 9, 700];

function compareFunction (a, b) {
    return a - b;
}

console.log(‘不指定比較函數的數字數組排列:‘ + numberArray.sort());
console.log(‘指定比較函數的數字數組排列:‘ + numberArray.sort(compareFunction));

Chrome輸出的結果:

不指定比較函數的數字字符串數組排列:700,80,9
指定比較函數的數字字符串數組排列:9,80,700

數字和數字字符串混合數組排列

創建一個數字和數字字符串混合數組之後進行排序,對比數組分別指定與不指定比較函數的結果:

var mixedNumericArray = [‘80‘, ‘9‘, ‘700‘, 40, 1, 5, 200];

function compareFunction (a, b){
    return a - b;
}

console.log(‘不指定比較函數的數組排列:‘ + mixedNumericArray.sort());
console.log(‘指定比較函數的數組排列‘ + mixedNumericArray.sort(compareFunction));

Chrome輸出的結果:

不指定比較函數的數組排列:1,200,40,5,700,80,9
指定比較函數的數組排列1,5,9,40,80,200,700

數字數組隨機排列

除了給數字數組進行升序或降序排列之外,還可以定義一個隨機函數,實現數組的隨機排列。定義的隨機函數返回正數或者負數,並表將隨機函數傳給sort()方法,此時sort()方法根據隨機函數返回的正負數來決定兩個值之前的位置。

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]

對象數組排列

對於對象數組排列,我們同樣需要先寫一個構造函數:

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的降序排列

來看看Chrome輸出的前後結果:

技術分享圖片

另外,只需要改變比較函數objectSort()中的desc參數值為flase,數組就會按object指定的property屬性降序排列:

console.log(myArray.sort(objectSort(‘age‘,false))); //按objcet中的age升序排列

Chrome輸出的前後結果:

技術分享圖片

除此之外,還有其的對比較函數,如下所示:

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‘))); // 按降序排列

上面介紹的是按一個屬性進行排序,但很多時候,希望按多個屬性排序,那麽比較函數需要做一定的調整:

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‘));

reverse()方法

reverse()方法相對而言要簡單得多,它就是用來顛倒數組中元素的位置,並返回該數組的引用。比如我們有一個數組:

var myArray = ["Airen","W3cplus","Blog"];
console.log(myArray.reverse()); // ["Blog", "W3cplus", "Airen"]

總結

本文主要介紹了數組中元素項的排序方法。而主要詳細介紹的是sort()方法。通過給sort()方法傳遞不同的比較函數,我們可以實現字符串數組數字數組數字和數字字符串混合數組對象數組等按順序(升序降序)排列。

JavaScript學習筆記:數組的sort()和reverse()方法