更好用的排序

Array.prototype.sort

在 ES5 中,已经对集合提供一个排序方法 Array.prototype.sort

var students = [
  {name: 'wxj', age: 18},
  {name: 'john', age: 14},
  {name: 'bob', age: 23}
];

var sortedStudents = students.sort(function(left, right) {
  return right.age < left.age;
});

// => sortStudents: [
//  {name: 'john', age: 14},
//  {name: 'wxj', age: 18},
//  {name: 'bob', age: 23},
//]

_.sortedBy

_.sortedBy(obj, iteratee): 根据比较条件 ieratee,对 obj 进行排序。

源码

_.sortBy = function (obj, iteratee, context) {
    var index = 0;
    iteratee = cb(iteratee, context);
    // 先通过map生成新的对象集合,该对象提供了通过iteratee计算后的值, 方便排序
    // [{value:1,index:0,criteria: sin(1)}, ...]
    // 再排序.sort
    // 最后再通过pluck把值摘出来
    return _.pluck(_.map(obj, function (value, key, list) {
        return {
            value: value,
            index: index++,
            criteria: iteratee(value, key, list)
        };
    }).sort(function (left, right) {
        var a = left.criteria;
        var b = right.criteria;
        if (a !== b) {
            if (a > b || a === void 0) return 1;
            if (a < b || b === void 0) return -1;
        }
        return left.index - right.index;
    }), 'value');
};

下面解释一下 _.sortBy 的工作流程:

  • 通过 _.map 生成一个新的集合,该集合的每个元素是一个对象,他具有三个属性:

    • value: 元素值
    • index: 索引位置
    • criteria:排序准则,该准则将通过被优化的 iteratee 计算得到。underscore 看到了元素间的比较仍将落脚到“值比较”的本质。

假设我们现在有集合:

var students = [
    {name: 'wxj', age: 18},
    {name: 'john', age: 14},
    {name: 'bob', age: 23}
];

假设我们需要按照年龄进行排序,那么传入的 iteratee 为:

var iteratee = function(value, key, index, elem) {
    return elem.age;
}

经过该过程,该集合将变为:

var newStudents = [
    {
      value: {name: 'wxj', age: 18},
      index: 0,
      criteria: 18
    },
    {
      value: {name: 'john', age: 14},
      index: 0,
      criteria: 14
    },
    {
      value: {name: 'bob', age: 23},
      index: 0,
      criteria: 23
    }
];
  • 利用 Array.prototype.sort 以及我们确定的排序准则 criteria 对新生成的集合进行排序:
var sortedStudents = newStudents.sort(function (left, right) {
  var a = left.criteria;
  var b = right.criteria;
  if (a !== b) {
      if (a > b || a === void 0) return 1;
      if (a < b || b === void 0) return -1;
  }
  return left.index - right.index;
});

// => sortedStudents: [
//    {
//      value: {name: 'john', age: 14},
//      index: 0,
//      criteria: 14
//    },
//    {
//      value: {name: 'wxj', age: 18},
//      index: 0,
//      criteria: 18
//    },
//    {
//      value: {name: 'bob', age: 23},
//      index: 0,
//      criteria: 23
//    }
//];
  • 再通过 _.pluck 取出 value 属性,过滤掉不需要的 indexcriteria 属性:
var ret = _.pluck(sortedStudents, 'value');
// => ret: [
//  {name: 'john', age: 14},
//  {name: 'wxj', age: 18},
//  {name: 'bob', age: 23},
//]

最后,我们看一看 _.sortBy 带来的便捷性:

var students = [
  {name: 'wxj', age: 18},
  {name: 'john', age: 14},
  {name: 'bob', age: 23}
];

var sortedStudents = _.sortBy(students, 'age');

// => sortStudents: [
//  {name: 'john', age: 14},
//  {name: 'wxj', age: 18},
//  {name: 'bob', age: 23},
//]

results matching ""

    No results matching ""