如何实现 Array.prototype.sort 默认比较功能?

Fla*_*nix 5 javascript sorting

背景

我需要实现一个与 Array.prototype.sort 的默认比较函数具有相同行为的函数

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

阅读文档后,我偶然发现了这一点:

默认排序顺序是根据字符串 Unicode 代码点。

这是什么意思?这是否意味着我将每个对象都转换为字符串?

如果是这样,假设我有数组[2, "a", { hello: "world" }],这些步骤是否正确?

  1. 转换[2, "a", { hello: "world" }]["2", "a", '{ hello: "world" }']
  2. 将每个字符串的第一个字符转换为数字
  3. 按那个号码排序

如何实现给定任何对象的比较函数,其行为与 sort 中的比较函数完全相同?

笔记

阅读ECMA规范:

我现在相信如果comparefnundefined,那么他们使用这个算法作为默认值:

http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare

有人可以确认吗?

Fla*_*nix 8

解决方案

在阅读了 ECMA 规范并四处询问后,我找到了一个模拟chrome 中defaultCompare默认行为的函数:Array.prototype.sort()

const defaultCompare = ( x, y ) => {
    //INFO: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
    //ECMA specification: http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare

    if( x === undefined && y === undefined )
        return 0;

    if( x === undefined )
        return 1;

    if( y === undefined )
        return -1;

    const xString = toString(x);
    const yString = toString(y);

    if( xString < yString )
        return -1;

    if( xString > yString )
        return 1;

    return 0;
};

const toString = obj => {
    //ECMA specification: http://www.ecma-international.org/ecma-262/6.0/#sec-tostring

    if( obj === null )
        return "null";

    if( typeof obj === "boolean" ||  typeof obj === "number" )
        return (obj).toString();

    if( typeof obj === "string" )
        return obj;

    if( typeof obj === "symbol" )
        throw new TypeError();

    //we know we have an object. perhaps return JSON.stringify?
    return (obj).toString();
};

module.exports = defaultCompare;
Run Code Online (Sandbox Code Playgroud)

我该如何测试它?

您可以像下面这样测试这个函数:

const arr = [ undefined, null, 3, 2, 'B', 'a', 'b', 'A',
{ hello: "world"}, { goodnight: 'moon'} ]

assertEql( arr.sort(), arr.sort(defaultCompare) ); //true
Run Code Online (Sandbox Code Playgroud)

如果您在同一浏览器中测试它们,则输出应该相同。