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