让我们假设我想要一个排序函数,它返回输入数组的排序副本。我很天真地试过

function sort(arr) {
  return arr.sort();
}

我用这个测试了一下,结果显示我的排序方法改变了数组。

var a = [2,3,7,5,3,7,1,3,4];
sort(a);
alert(a);  //alerts "1,2,3,3,3,4,5,7,7"

我也尝试过这种方法

function sort(arr) {
  return Array.prototype.sort(arr);
}

但它根本不起作用。

有没有一种直接的方法来解决这个问题,最好是一种不需要手动滚动我自己的排序算法或将数组中的每个元素复制到一个新的数组中的方法?


当前回答

有一个新的tc39提案,它向Array添加了一个toSorted方法,该方法返回数组的副本,而不修改原始数组。

例如:

const sequence = [3, 2, 1];
sequence.toSorted(); // => [1, 2, 3]
sequence; // => [3, 2, 1]

由于它目前处于第3阶段,可能很快就会在浏览器引擎中实现,但与此同时,polyfill可以在这里或core-js中使用。

其他回答

您还可以扩展现有的Array功能。这允许将不同的数组函数链接在一起。

Array.prototype.sorted = function (compareFn) {
    const shallowCopy = this.slice();
    shallowCopy.sort(compareFn);

    return shallowCopy;
}

[1, 2, 3, 4, 5, 6]
    .filter(x => x % 2 == 0)
    .sorted((l, r) => r - l)
    .map(x => x * 2)

// -> [12, 8, 4]

typescript中相同:

// extensions.ts
Array.prototype.sorted = function (compareFn?: ((a: any, b: any) => number) | undefined) {
    const shallowCopy = this.slice();
    shallowCopy.sort(compareFn);

    return shallowCopy;
}

declare global {
    interface Array<T> {
        sorted(compareFn?: (a: T, b: T) => number): Array<T>;
    }
}

export {}

// index.ts
import 'extensions.ts';


[1, 2, 3, 4, 5, 6]
    .filter(x => x % 2 == 0)
    .sorted((l, r) => r - l)
    .map(x => x * 2)

// -> [12, 8, 4]

有一个新的tc39提案,它向Array添加了一个toSorted方法,该方法返回数组的副本,而不修改原始数组。

例如:

const sequence = [3, 2, 1];
sequence.toSorted(); // => [1, 2, 3]
sequence; // => [3, 2, 1]

由于它目前处于第3阶段,可能很快就会在浏览器引擎中实现,但与此同时,polyfill可以在这里或core-js中使用。

只需要复制数组。有很多方法可以做到这一点:

function sort(arr) {
  return arr.concat().sort();
}

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects

试试下面的方法

function sortCopy(arr) { 
  return arr.slice(0).sort();
}

slice(0)表达式从元素0开始创建数组的副本。

任何想要做深度复制的人(例如,如果你的数组包含对象)可以使用:

let arrCopy = JSON.parse(JSON.stringify(arr))

然后你可以在不改变arr的情况下对arcopy进行排序。

arrCopy.sort((obj1, obj2) => obj1.id > obj2.id)

请注意:对于非常大的数组,这可能会很慢。