[10, 2, 1].sort() 在 JS 中会输出什么
在准备面试题的时候,想起了一个在 18 年掉过的坑。关于 JavaScript 中 Array.prototype.sort()
的默认排序数据类型。
(希望问别人这个问题,不会在背后被人骂。)
是什么 #
一些没掉过坑的同学,可能会说当然是 [1, 2, 10]
啦。
但是如果你看过 MDN 的关于 Array.prototype.sort()
的文档,你就会知道这个结果是错误的,文档中的第一句话和第二例子就是对这个问题的描述。
那么,答案是什么呢,答案是 [ 1, 10, 2 ]
。
为什么呢,看 MDN 原文:
The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.
sort()
函数的默认排序是正序,以及排序的的时候会把所有元素都转化成字符串,然后再排序。字符串排序首先是按照第一个字符进行排序的,再者第一个字符相同的排第二个字符,所以最后的结果是 [ 1, 10, 2 ]
。
然而编译器为什么要这么做呢?
为什么 #
首先当然是语言的标准定义这么做的,编译器只是对标准的实现。在 JS 中这个标准就是 ECMAScript 。
在 Array.prototype.sort()
的标准定义中说:
d. If comparefn is not undefined, then
i. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
ii. If v is NaN, return +0𝔽.
iii. Return v.
e. Let xString be ? ToString(x).
f. Let yString be ? ToString(y).
g. Let xSmaller be ! IsLessThan(xString, yString, true).
上面的意思是说,如果 sort 中没有传入比较函数,那么就将需要比较的元素,进行 ToString()
转化后在比较。
那么为什么标准需要这么处理呢?
这里我大胆的猜一猜,找一找借口...。
- 首先
sort()
函数并不是指针对数字进行排序的,还有其他所有类型都可以传入,为了保证函数的语意明确,统一进行ToString()
操作。 - 其次我们看下
ToString()
在规范中的定义,除了对 Symbol 类型调用ToString()
会抛异常,其他类型都是可以使用ToString()
转化的,所以这也是一个的把未知转化成已知类型的操作,非常干净。
所以为什么不对数字进行特殊处理呢?这就不知道了,不过我们可以站语言标准的制定者的角度思考的问题角度,你愿意在标准中让一些方法对一个类型进行特殊处理吗?
题外话,基于以上 ToString()
的例子,我想到有些很奇怪的面试考就是考你,对特殊类型进行加号操作会输出什么,不外呼就是转型成 String 后拼接。
怎么做 #
那么就传入排序函数吧。
[10, 2, 1].sort((a, b) => a - b);
- Previous: 关于 if/else 和 for 的可读性问题
- Next: 在 Bash 中快速执行历史命令的小技巧