有什么方法可以扩展 javascript 的 array.sort()方法来接受另一个参数吗?

我正在尝试对对象数组进行排序。我不希望为每个属性编写自定义排序方法。

我是否可以扩展内置的 array.sort()方法来接受一个额外的参数,描述要排序的属性?例如:

array.sort(function(a, b, attr) { return a.attr - b.attr; }, 'name');
38440 次浏览

编写一个接受属性名的函数生成器:

function propComparator(prop) {
return function(a, b) {
return a[prop] - b[prop];
}
}


arr.sort(propComparator('name'));

您还可以将排序器保存起来,以便以后直接使用,或者作为参数使用:

var compareNames = propComparator('name');
var compareFoos = propComparator('foo');
...
arr.sort(compareNames);
takesComparator(compareFoos);

更新为 ES6,并使其实际上与不同类型的工作。

Note that sort sorts in-place, which may or may not be desirable.

const arr = [
{ name: 'John', age: 92 },
{ name: 'Dave', age: 42 },
{ name: 'Justin', age: 3 }
]


const propComparator = (propName) =>
(a, b) => a[propName] == b[propName] ? 0 : a[propName] < b[propName] ? -1 : 1


arr.sort(propComparator('name'))
console.log("By name", arr)


arr.sort(propComparator('age'))
console.log("By age", arr)

Is this what you're looking for?

function sortByProperty(array, propertyName) {
return array.sort(function (a, b) {
return a[propertyName] - b[propertyName];
});
}


var sortedByName = sortByProperty(myArray, "name");

使用原型正确地比较字符串和数字

Array.prototype.sortAttr = function(attr,reverse) {
var sorter = function(a,b) {
var aa = a[attr];
var bb = b[attr];
if(aa+0==aa && bb+0==bb) return aa-bb; // numbers
else return aa.localeCompare(bb); // strings
}
this.sort(function(a,b) {
var result = sorter(a,b);
if(reverse) result*= -1;
return result;
});
};

例子

var data = [
{name: "Josh", age: 18},
{name: "John", age: 17},
{name: "Bob", age: 20},
{name: 0, age: "error"}
];


data.sortAttr("name");
// data is now sorted by name

我是否可以扩展内置的 array.sort ()方法来接受额外的参数

以上的答案都很好。但是我想增加一些关于部分函数的信息

更多信息请参见 MDN 和 部分函数或 John Resig-部分函数中的 bind

来自 MDN 的例子:

function list() {
return Array.prototype.slice.call(arguments);
}


var list1 = list(1, 2, 3); // [1, 2, 3]


//  Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);


var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

这里有一个来自 谷歌关闭的例子

goog.partial = function(fn, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
// Prepend the bound arguments to the current arguments.
var newArgs = Array.prototype.slice.call(arguments);
newArgs.unshift.apply(newArgs, args);
return fn.apply(this, newArgs);
};
};

使用此函数

    var fn=goog.partial(numberCompare,sortField,sortDirection);
myarray.sort (fn);




var numberCompare = function (sortField,sortDirection,value1,value2){
// sort code goes here
}

实际上是延伸

In order to actually extend Array.prototype.sort, we have a couple options:

  • Mutate its 签名
  • 使用 装潢师 | 适配器(父模式: 包装纸)进行多重排序

我和你处境一样,决定用第二种方法:

private sortAddresses = (a, b) => {
let iPrimeFlag = this.sortAddressesByPrimaryFlag(a, b);
let iAlphaNum = this.sortAddressesByAlphaNum(a, b);


if (iPrimeFlag === 1) return 1;
else return iAlphaNum;
};


private sortAddressesByPrimaryFlag(a, b) {
if (b.primaryFlag > a.primaryFlag) return 1;
if (b.primaryFlag < a.primaryFlag) return -1;
return 0;
}


private sortAddressesByAlphaNum(a, b) {
let aAddress = this.$.formatAddress(a);
let bAddress = this.$.formatAddress(b);


if (aAddress > bAddress) return 1;
if (aAddress < bAddress) return -1;


return 0;
}

意图

我已经打电话给 this.addresses.sort(this.sortAddresses) 在几个地方,我想保持我的 更改成本低-特别是,知道我们可能会有要求排序的 更多的启发

因此,为了遵循 四人帮的两条“经验法则”-

程序的接口,而不是实现。

还有

把不同的封装起来。

我决定保持我的 签名不变并包装我的原始方法。

如果我们不需要遍历和更改调用 this.addresses.sort的每一行,那么这将非常有用。相反,我们希望能够在排序操作中添加一个 不确定数量的排序“启发式”。

目标是对 primaryFlag'Y'的地址对象进行优先级排序,然后获取地址字符串 '0000 Some St, #0000, City, ST 00000',并按字母数字对这些地址对象进行排序。由于 'Y'> 'N',我们希望通过降低它的索引,在视觉上将它移动到列表中的 'Y'0。对地址字符串进行字母数字排序表明,如果 'Colorado'> 'Alabama',那么我们应该通过增加其索引,在列表中直观地突破 'Colorado' 'Y'1。

Usage

这用于按不同值对 primaryFlag0进行排序。其中一个值 primaryFlag表示它是否是[唯一]默认地址; 在我的例子中,它是 primaryFlag primaryFlag1(请问我的后端队友为什么这么做?).另一个值 this.$.formatAddress(a|b)接受这些地址 [object Object]的—— ab——并从我的 primaryFlag2 this.$调用 formatAddress

if (iPrimeFlag === 1) return 1;是说,“任何时候,主标志是1,只是撞击它的头部(开始)的数组,否则,做任何字母数字启发决定”,这使我们能够 分清轻重缓急的一个启发,而落在另一个。

还要注意的是,.bind(undefined, 'prop')not,因为我不需要它,所以在我的实际代码中使用;。

现在,我知道我就是那个提供了一些 TypeScript的人——如果您不理解这段代码中发生了什么,请告诉我:)

干杯!

如果有人需要升序,这里是戴夫牛顿的解决方案与反向选项

const sorton = (prop, asc=0) => {
if(!asc) return (a, b) => a[prop] == b[prop] ? 0 : a[prop] < b[prop] ? -1 : 1
else return (b, a) => a[prop] == b[prop] ? 0 : a[prop] < b[prop] ? -1 : 1
}

arr.sort(propComparator('age', 1))

In Typescript it is simple. I had created a little different sorting function for string sorting. Since Array.sort takes a function, you can also pass closure. So my sorting function is:

sortCaseInsensitive(a,b,column:string) {
return (a[column]? a[column] : '').toLowerCase().
localeCompare((b[column]? b[column] : '').toLowerCase());
}

如果我的数据是

    [
{ value:'a', label:'a1'}
{ value:'b', label:'b1'}
]

然后,你可以打电话:

arrayList123.sort((a,b)=>myself.sortCaseInsensitive(a,b,'value'));

There you can pass any arguments. Sweet and simple.