摘要:然而有時候的結果和預期結果還是有些差異的。中文的可以通過來獲取。啊次比例中毓比侊啊比侊比例次毓中當然和允許傳入參數指定,有興趣的可以去上看看用法。對于中文或者需要本地化比較的場景下,可以使用或者來進行比較。
大家都知道 js 自帶了一個排序方法 sort,很多時候需要排序的時候也都直接使用了 sort 方法來排序。然而有時候 sort 的結果和預期結果還是有些差異的。
看下面的代碼
[1, 23, 2, 3].sort()
自然語言情況下,我們期望的 排序結果應該是 [1,2,3,23] ,然而實際結果 [1, 2, 23, 3] 。
首先我們來看下各個瀏覽器( js 引擎) 的排序算法。
瀏覽器 | 使用的 JavaScript 引擎 | 排序算法 | 源碼地址 |
---|---|---|---|
Google Chrome | V8 | 插入排序和快速排序 | sort 源碼實現 |
Mozilla Firefox | SpiderMonkey | 歸并排序 | sort 源碼實現 |
Safari | Nitro(JavaScriptCore ) | 歸并排序和桶排序 | sort 源碼實現 |
Microsoft Edge 和 IE(9+) | Chakra | 快速排序 | sort 源碼實現 |
注:上述表格數據來源于 排序算法 |
以 v8 為例, 它分別使用了 插入排序和 快速排序,分別使用的場景 可以查看源碼,也可以看 justjavac 大佬的這篇文章 ,同時這篇文章也分析了一個排序的坑。
當 sort 沒傳遞 compareFn 的時候,就會使用默認的 compareFn ,而 sort 很多的坑都源于這里。 根據 justjavac 大大的那篇文章里的分析和 ecma 標準里的聲明,我們得知compareFn 會在內部嘗試調用 toString 將比較的對象轉化成字符串。
在轉化成字符串這一步之后,坑就出現了。當 x 和 y (這里 x、 y 都已經是字符串了)進行比較的,其實是依據字典序來比較的,而比較的對象其實數據的 charCode。
字典序的比較方法引用一下 維基百科上的說法:
是先按照第一個字母、以 a、b、c……z 的順序排列;如果第一個字母一樣,那么比較第二個、第三個乃至后面的字母。如果比到最后兩個單詞不一樣長(比如,sigh 和 sight),那么把短者排在前。
因此,在 [1, 23, 2, 3].sort() 中,比較的時候其實是 "1"、"23"、"2"、"3"、 來進行比較的(注意引號,是字符串)。 下面是這些字符串的 charCode 表:
1 | 23 | 2 | 3 |
---|---|---|---|
49 | 50 51 | 50 | 51 |
"1" 和 "23" 比較,先比較第一位 charCode, 49 小于50,直接判定成功,"1"<"23" ,而 "23" 和 "2" 比較,第一位 charCode 相同,判斷不了,看第二位; 而第二位上 一個是 51,一個是”空“ 的,因此 2 < 23。而"23" 和 "3" 比較, 由于2的 charCode 小于 3 的, 因此也直接判定成功,23 < 3。
類比可以考慮一下我們小學時候使用的字典 ,字典前面的拼音索引, ai 的拼音也始終在 ba 前面,因為 a 的字典序小于 b 。
同樣的,來看下英文: ["a","ba","b","c","ca"] 。
a | b | ba | c | ca |
---|---|---|---|---|
97 | 98 | 98 97 | 99 | 97 |
根據上面的規則,我們可以很容易推斷出排序結果: ["a", "b", "ba", "c", "ca"]
最后看看中文的: ["啊","次","比例","中","毓","比侊"]
啊 | 次 | 比例 | 中 | 毓 | 比侊 |
---|---|---|---|---|---|
21834 | 27425 | 27604 20363 | 20013 | 27603 | 27604 20362 |
同樣的,根據上面的規則,結果也是一目了然:["中", "啊", "次", "毓", "比侊", "比例"]。
中文的 charCode可以通過 charCodeAt 來獲取。
這樣的排序結果很多時候并不是我們需要的,因此 sort 也允許我們傳入一個 compareFn 來實現自定義排序規則,通過返回 -1、0、1 來覺得排序結果的大小順序。對于可以比較的數值,我們可以通過 x-y 的方式來處理,那么中文又該怎么辦呢?能不能按照拼音的順序來排序?
答案是肯定的!
String 現在有了一個 localeCompare 的方法用于本地化比較。
["啊","次","比例","中","毓","比侊"].sort((x,y) => x.localeCompare(y)) // ["啊", "比侊", "比例", "次", "毓", "中"]
在 MDN 中,在涉及到大量比較的時候更推薦的是 Intl.Collator。 Intl 對象是 ECMAScript 國際化 API 的一個命名空間,它提供了精確的字符串對比,數字格式化,日期和時間格式化。
const collator = new Intl.Collator() ["啊","次","比例","中","毓","比侊"].sort(collator.compare) // ["啊", "比侊", "比例", "次", "毓", "中"]
當然 localeCompare 和 Intl.Collator 允許傳入參數指定 locale, 有興趣的可以去 MDN 上看看用法。
最后,內置 sort 的默認 compareFn 方法是基于字典序排序的, 而字典序比較的對象是 數據的 charCode。當 sort 默認的排序行為和預期不一樣或者無法滿足需求的時候,我們可以傳入自定義的 compareFn 來進行排序。對于中文或者需要本地化比較的場景下,可以使用 String.localeCompare 或者 Intl.Collator 來進行比較。
最后的最后,如有錯誤,歡迎大家指出,一起討論進步。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108624.html
摘要:使用把指定運算結果為的數組元素添加到二維數組的第一個數組中,運算結果為的數組元素添加到二維數組的第二個數組中。所以改成了,它是不改變數組元素的,沒有副作用,不干擾后續。方法將剩余的所有數組元素以的方式返回結果數組。 原文地址:JavaScript30秒, 從入門到放棄之Array(四)博客地址:JavaScript30秒, 從入門到放棄之Array(四) 水平有限,歡迎批評指正 ma...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
閱讀 1686·2021-09-22 10:02
閱讀 1931·2021-09-02 15:40
閱讀 2835·2019-08-30 15:55
閱讀 2243·2019-08-30 15:44
閱讀 3593·2019-08-30 13:18
閱讀 3224·2019-08-30 11:00
閱讀 1945·2019-08-29 16:57
閱讀 564·2019-08-29 16:41