如何让JavaScript自定义数值类无需额外比较函数即可被sort()排序?
自定义类实例数组无需额外比较函数实现排序的方案
答案是可以实现,但不能靠重写toString()——因为toString()的字符串转换逻辑根本适配不了数值排序(比如默认排序会把20排在3前面)。下面给你两种实用方案:
方案1:用Symbol.toPrimitive让对象自动转数值
JavaScript里有个Symbol.toPrimitive方法,专门用来定义对象转成原始值的规则。数组默认的sort()会把元素转成原始值再比较,我们重写这个方法返回实例的数值,就能让sort()直接按数值排序,不用传任何额外函数:
class NumericSortable { constructor(newVal) { this.val = newVal } [Symbol.toPrimitive](hint) { return this.val; } } const objectList = [ new NumericSortable(3), new NumericSortable(1), new NumericSortable(20), ]; objectList.sort(); // 直接调用,不用传参数 console.log(objectList); // 输出按val升序排列的数组
原理很简单:当sort()处理对象时,会自动触发Symbol.toPrimitive把对象转成数值,然后就会用数值的比较逻辑排序,完全符合需求。
方案2:静态比较方法简化调用(备选)
如果不想用Symbol.toPrimitive,也可以给类加个静态比较方法,调用时直接传这个方法就行——虽然还是要传参数,但不用每次写匿名函数,更省心:
class NumericSortable { constructor(newVal) { this.val = newVal } static compare(a, b) { return a.val - b.val; } } const objectList = [ new NumericSortable(3), new NumericSortable(1), new NumericSortable(20), ]; objectList.sort(NumericSortable.compare); console.log(objectList);
为什么toString()不行?
要是你重写toString()返回this.val.toString(),sort()会按字符串的Unicode编码排。比如"20"的第一个字符"2"码点比"3"小,所以20会排在3前面,这显然不是你要的数值排序结果,所以这个路子走不通。
内容的提问来源于stack exchange,提问作者Jim K
相关产品推荐
相关产品推荐

