首页
学习
活动
专区
工具
TVP
发布

浅谈 JavaScript中sort 排序的坑

Array 数组的排序受关注度一直就不高,除非当它出现了问题。最近我在项目中就遇到了一个数组排序问题,数组中的项没有按我预想的被排序,导致界面上无法正常显示。我花了很长的时间才明白问题究竟出在哪里,所以想在这里和大家分享一下。

基本排序

JS 中的 Array 对象有一个排序方法sort( ),调用它的运行结果一般来说是这样的:

甚至当数组中出现未定义值的元素时sort( )也同样好用。文档中有这样一句话:

“所有未定义的数组元素都会被转化成字符串,并通过比较 UTF-16 的值来进行排序。”

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

一些陷阱

使用排序时你可能会遇到的第一个问题就是当数组中有null时。排序方法会强行把空值转换成字符串"null",而 n 位于字母表大概中间的一个位置。

然后就是数字。排序方法的默认算法是将数组内全部元素转成一个字符串数组,再比较它们的 UTF-16 编码。如之前所见,在元素为字符串时这个方法很好用,但碰见数字元素时就尴尬了。

如上图所示,在这个例子中运行结果里 10 排在 3 之前,因为字符串"10"排在字符串"3"之前。

我们可以通过给 JS 提供一个用于排序的比较函数来解决这个问题。函数从数组对象中接收两个元素并返回一个数字的值,该值是大于,小于或是等于零决定了这两个数字排序时的位置。比方说如果返回值为负数,第一个元素就会被排在第二个元素之前,如果值为0则证明两个元素等值。

要升序排列这些数字,函数的写法很简单。用两个元素相减,符合我们的描述,最终也会得出正确的排序。我们把这个函数提供给 JS 排序的方法,和下图中一样:

注意这个解决方案同样适用于当有元素未定义时,因为未定义元素默认排在末尾。

不过null仍然是一个问题。

因为将null放入数字转换方法中得到的是 0。

你可以通过再次改进之前所写的compareNumbers函数,或者勉强继续使用。

排序结果不一致性

最大的问题,也就是最近我才发现的问题,就是当undefined未定义以其它的方式进入到数组中。之前我们已经知道如果有未定义的元素,它默认会被排到末尾。然而如果被排序的对象,键是未定义的话,出现的结果就会不一致。

比方说,你有一个对象数组,其中一些对象有值,一些对象没有,排序的结果可能与你的预期产生偏差。

用 undefined 减去一个数字或者用数字减去undefined都会返回NaN,NaN并不在数字比较方法返回值的范围中,因为它或为正或为负或等于0,所以最后的排序结果会很奇怪。本例中,引发问题的元素位置不变,该元素上下的数字仅仅被局部排序。

这个问题的解决方法有几个,但重要的就是我们需要知道它是有可能发生的。在我的项目中,我直接过滤掉了没有值的数组元素。

结论

上文分析的结果就在于sort( )排序方法并不如我们所想象的那么直接和易用。字符串排序没有问题,数字排序需要额外的操作但也能实现,虽然方法本身对undefined已经有处理方法,但我们必须格外小心对undefined和null对象的强制转型。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190829A0JO2S00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券