JavaScript中的Array.prototype.sort方法詳解

前幾天在某公司面試的時候被問到關於這個方法的默認值的問題(然而面試官跟我說的實際上是錯的,當場我還不夠底氣去反駁)。忽然發現對這個方法的瞭解還不夠,所以回來查了資料,看了v8引擎的實現和ECMA標準,在這分享一下個人總結。git

先給幾個結論把,而後咱們再從ECMA標準去看這個方法。github

  1. sort方法會修改本來數組。
  2. sort方法是不穩定的。
  3. sort方法能夠接受一個可選的參數,comparefn(比較回調函數)。
  4. sort方法始終是默認升序的。

1.sort方法會修改本來數組

let a = [1, 20, 13, 110]
a.sort()
console.log(a) // 輸出[1, 110, 13, 20]

如上,a在調用sort方法後,自身數組被修改。面試


2.sort方法是不穩定的

這句話具體來講應該是,sort方法在長數組排序的時候是不穩定的。在v8引擎的裏,對於短數組會使用插入排序,而插入排序是穩定的。對於長數組會使用快速排序,而快速排序通常是不穩定的。具體能夠讀v8引擎的代碼,v8引擎內的數組方法實現,從710行開始。算法


3.sort方法能夠接受一個可選的參數,ccomparefn(比較回調函數)。

咱們來看一下v8引擎中關於這一部分的代碼數組

if (!IS_CALLABLE(comparefn)) {
    comparefn = function (x, y) {
      if (x === y) return 0;
      if (%_IsSmi(x) && %_IsSmi(y)) {
        return %SmiLexicographicCompare(x, y);
      }
      x = TO_STRING(x);
      y = TO_STRING(y);
      if (x == y) return 0;
      else return x < y ? -1 : 1;
    };
  }

能夠看出,在不傳遞comparefn這個參數的狀況下,默認會使用轉換爲的字符串的諸個字符的Unicode位點進行排序。另外值得注意的一點是,undefined在默認狀況下老是會被排在數組的最後,這一點能夠參考ECMA-262標準中關於Array.prototype.sort(comparefn)的描述。瀏覽器

When the SortCompare operatoris called with two arguments x and y, the
following steps are taken:ide

  1. If x and y are both undefined, return +0.
  2. If x is undefined, return 1.
  3. If y is undefined, return −1.
  4. If the argument comparefn was not provided in the call to sort, go to step 7.
  5. Call comparefn with arguments x and y.
  6. Return Result(5).
  7. Call ToString(x).
  8. Call ToString(y).
  9. If Result(7) < Result(8), return −1.
  10. If Result(7) > Result(8), return 1.
  11. Return +0.

如下是我簡單翻譯的規則:函數

當比較操做函數用x,y兩個參數調用的時候,會按照接下來的步驟進行:prototype

  1. 若是x,y都是undefined,返回 +0
  2. 若是x是undefined,返回 1
  3. 若是y是undefined,返回 -1
  4. 若是沒有提供comparefn,跳至第七步
  5. 用comparefn比較x,y
  6. 返回第五步的比較結果
  7. x.toString()
  8. y.toString()
  9. 若是第八步大於第七步,返回-1
  10. 若是第七步大於第八步,返回1
  11. 返回+0

所以[1, 20, 2, 10].sort()的結果會是[1, 10, 2, 20],而不是預期的[1, 2, 10, 20]。翻譯


4. sort方法始終是默認升序的。

另外關於如何根據x,y比較結果進行排序,有如下規則:

  • 若是 comparefn(a, b) 小於 0 ,那麼 a 會被排列到 b 以前;
  • 若是 comparefn(a, b) 等於 0 , a 和 b 的相對位置不變。備註: ECMAScript 標準並不保證這一行爲,並且也不是全部瀏覽器都會遵照(例如 Mozilla 在 2003 年以前的版本, 例如v8引擎, 這一點其實就是上面所說的排序不穩定);
  • 若是 comparefn(a, b) 大於 0 , b 會被排列到 a 以前。

因此sort方法返回的數組永遠是該方法認爲的升序數組。咱們要作的事情就是令咱們想要放在後面的數大於放在前面的數。

好比咱們想要返回一個降序的數字數組傳入的comparefn應該是 (a, b) => b - a

參考資料:

  1. MDN關於sort算法的文檔
  2. v8引擎數組實現
  3. ECMA-262標準
相關文章
相關標籤/搜索