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

IT技术 javascript sorting
2021-03-16 00:04:59

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

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

array.sort(function(a, b, attr) { return a.attr - b.attr; }, 'name');
6个回答

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

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 进行了更新,并使其实际适用于不同的类型。

请注意,sort就地排序,这可能是也可能不是理想的。

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)

谢谢戴夫,我在传递变量来对对象数组进行排序时遇到了麻烦,这非常有效!
2021-04-20 00:04:59
@mivaas19 它之所以有效,是因为您可以传递函数引用,无论是直接函数,就像您经常使用 jQuery 事件处理程序看到的那样,还是命名函数,您只需去掉括号即可。这是一个非常强大的工具。
2021-04-29 00:04:59
TIL:函数发生器!
2021-05-13 00:04:59
在这里直播。jsfiddle.net/mivaas19/AMukX很好的答案;但我仍然想知道它是如何工作的。
2021-05-14 00:04:59
我喜欢闭包。了不起的他们
2021-05-16 00:04:59

这是你要找的吗?

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

var sortedByName = sortByProperty(myArray, "name");
我没有看到两个版本之间的巨大差异;@DaveNewton,你能解释一下你的评论吗?另外,多亏了你们两个,两个答案看起来都有效......
2021-04-25 00:04:59
@danwoods 区别在于沟通之一:我更喜欢将数组作为声明中的主要参与者的更具功能性/OOP 外观的方法:arr.sort(how)对我而言,它比how(arr, moreHow). 此外,生成的函数作用于任何具有名称属性的东西,而不是包装特定于数组或sort特定于函数的实体。
2021-05-05 00:04:59
一个会给你一个比较函数(Daves),另一个使用匿名函数。因此,如果您想要比较功能,请使用提供它的功能。
2021-05-15 00:04:59

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

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
@d.popov 你真是一位考古学家!6 年前 localeCompare 有问题,现在是时候更新了。感谢您的成功捕捉,递归太可怕了,当时我太天真了......
2021-04-17 00:04:59
代码有时会抛出“递归过多”异常。建议修改排序器以使用 localeCompare() 而不是自定义定义的比较。
2021-05-02 00:04:59
原型与否不是字符串与数字的问题,而是提供的排序函数的问题。
2021-05-04 00:04:59

无论如何我可以扩展内置的 array.sort() 方法来接受额外的参数

以上所有答案都很好。但我想添加一些关于部分功能的信息

有关更多信息,请参阅 MDN 中的绑定和部分函数或 John Resig -部分函数

来自 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
    }

如果有人需要升序,这里是 DaveNewton 的带有反向选项的解决方案

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))