![762343f0f95726e6c0b841df896751c2.png](https://i-blog.csdnimg.cn/blog_migrate/357e667af7f9a3723bfa65a72545cdc4.jpeg)
Array 数组的排序受关注度一直就不高,除非当它出现了问题。最近我在项目中就遇到了一个数组排序问题,数组中的项没有按我预想的被排序,导致界面上无法正常显示。我花了很长的时间才明白问题究竟出在哪里,所以想在这里和大家分享一下。
基本排序
JS 中的 Array 对象有一个排序方法 sort( ),调用它的运行结果一般来说是这样的:
![afbd07652f7fd49d1ab50fc85bb682ee.png](https://i-blog.csdnimg.cn/blog_migrate/1ce06e54aaad357689338f9867a285ab.jpeg)
甚至当数组中出现未定义值的元素时 sort( ) 也同样好用。文档中有这样一句话:
“所有未定义的数组元素都会被转化成字符串,并通过比较 UTF-16 的值来进行排序。”https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
![8212f0b0b141b0d1799c891395f731e0.png](https://i-blog.csdnimg.cn/blog_migrate/dc4d14ee8e59149cdbe947491dca9b14.jpeg)
一些陷阱
使用排序时你可能会遇到的第一个问题就是当数组中有 null 时。排序方法会强行把空值转换成字符串"null",而 n 位于字母表大概中间的一个位置。
![cdfde3af7bb1c0697149c0ad1151bf24.png](https://i-blog.csdnimg.cn/blog_migrate/f98c5b84db979a462a849e5cda29b843.jpeg)
然后就是数字。排序方法的默认算法是将数组内全部元素转成一个字符串数组,再比较它们的 UTF-16 编码。如之前所见,在元素为字符串时这个方法很好用,但碰见数字元素时就尴尬了。
![aca580c813c447323932ebf8e0d9f4f3.png](https://i-blog.csdnimg.cn/blog_migrate/a6259587eaa7df16944f75bd825e37ed.jpeg)
如上图所示,在这个例子中运行结果里 10 排在 3 之前,因为字符串"10"排在字符串"3"之前。
我们可以通过给 JS 提供一个用于排序的比较函数来解决这个问题。函数从数组对象中接收两个元素并返回一个数字的值,该值是大于,小于或是等于零决定了这两个数字排序时的位置。比方说如果返回值为负数,第一个元素就会被排在第二个元素之前,如果值为0则证明两个元素等值。
要升序排列这些数字,函数的写法很简单。用两个元素相减,符合我们的描述,最终也会得出正确的排序。我们把这个函数提供给 JS 排序的方法,和下图中一样:
![b0f2cead29fb72af86603bbe8138c6c1.png](https://i-blog.csdnimg.cn/blog_migrate/3b6a5e011a97bb66d291a6627c35eb33.jpeg)
![9674508cd274dd6065031e0bdb6fc2ef.png](https://i-blog.csdnimg.cn/blog_migrate/55efdd2e33476d9d15daa5f9e60a4f09.jpeg)
注意这个解决方案同样适用于当有元素未定义时,因为未定义元素默认排在末尾。
![5c9991ac2ddfbe9e78af520fd837b34e.png](https://i-blog.csdnimg.cn/blog_migrate/4a820dc1ac9c6b48a6757917d0f5233b.jpeg)
不过 null 仍然是一个问题。
![58c28b5c68c88c5cd114436fa9aea196.png](https://i-blog.csdnimg.cn/blog_migrate/c24b81948c24fa5985147eb5348f528d.jpeg)
因为将 null 放入数字转换方法中得到的是 0。
![6b253c2066a53c73cc9a3d62fd665d29.png](https://i-blog.csdnimg.cn/blog_migrate/54e42c3a0fcc85dc2f74b6da1798f82d.jpeg)
你可以通过再次改进之前所写的 compareNumbers 函数,或者勉强继续使用。
排序结果不一致性
最大的问题,也就是最近我才发现的问题,就是当 undefined 未定义以其它的方式进入到数组中。之前我们已经知道如果有未定义的元素,它默认会被排到末尾。然而如果被排序的对象,键是未定义的话,出现的结果就会不一致。
比方说,你有一个对象数组,其中一些对象有值,一些对象没有,排序的结果可能与你的预期产生偏差。
![da4da478f947550b3823c1f4caee0cf7.png](https://i-blog.csdnimg.cn/blog_migrate/d0049e2182a3ae98c028a4d6b65dd385.jpeg)
用 undefined 减去一个数字或者用数字减去 undefined 都会返回 NaN,NaN 并不在数字比较方法返回值的范围中,因为它或为正或为负或等于0,所以最后的排序结果会很奇怪。本例中,引发问题的元素位置不变,该元素上下的数字仅仅被局部排序。
这个问题的解决方法有几个,但重要的就是我们需要知道它是有可能发生的。在我的项目中,我直接过滤掉了没有值的数组元素。
![9409f0b3fd887295e2e806dc135e54c3.png](https://i-blog.csdnimg.cn/blog_migrate/7fe15af0baa6ff110bf9d1d2408adcaa.jpeg)
结论
上文分析的结果就在于 sort( ) 排序方法并不如我们所想象的那么直接和易用。字符串排序没有问题,数字排序需要额外的操作但也能实现,虽然方法本身对 undefined 已经有处理方法,但我们必须格外小心对 undefined 和 null 对象的强制转型。
微信搜索 “ng_4bytes” 关注4字节官方微信号,获取IT界一手资讯,更有免费程序员培训课程等你来拿!