关于javascript的排序功能

时间:2011-06-22 14:39:52

标签: javascript sorting

背景

根据某些任务的需要,我需要一个简单的排序功能。为简单起见,我编写了另一个函数来将内置排序函数包装为:

function sortBy(obj, extra, func){
    if(typeof func == 'function'){
        f = func;
    } else if(typeof extra != 'function'){
        eval('function f(a, b, ai, bi, e){return ' + func + '}');
    } else {
        var f = extra;
        extra = null;
    }

    var res = [];
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
            obj[i]._k_ = i;
            res.push(obj[i]);
        }
    }

    res.sort(function(a, b){
        if(f(a, b, a._k_, b._k_, extra)){
            return 1;
        } else {
            return -1;
        }
    })

    return res;
}

我的尝试是:

  1. 可以直接对对象进行排序
  2. 将原始对象保留为哈希表
  3. 允许一些简单的语法
  4. 例如,

    var data ={
        12: {age:27, name:'pop', role: 'Programmer'},
        32: {age:25, name:'james', role: 'Accontant'},
        123:{age:19, name:'jerry', role:'Sales Representative'},
        15:{age:22, name:'jerry', role:'Coder'},
        17:{age:19, name:'jerry', role:'Tester'},
        43:{age:14, name:'anna', role: 'Manager'},
        55: {age:31, name:'luke', role:'Analyst'}
    };
    

    有几种用法:

    var b = sortBy(data, '', 'a.age < b.age'); // a simple sort, order by age
    var b = sortBy(data, 19, 'b.age == e');    // pick up all records of age 19, and put them in the beginning
    var b = sortBy(data, function(a, b){return a.name > b.name});  // anonymous sort function is also allowed
    

    问题

    虽然它在我们的代码中按预期工作,但我想提出一些问题:

    1. 使用eval从字符串创建排序函数是否存在任何问题?
    2. 是否有关于排序函数返回-1(nagative),0和1(正数)的故事? 我们可以将代码更改为“if if(f(a,b,a。 k ,b。 k ,extra)”,而不是返回1或-1?我们发现它适用于我们的firefox和chrome,但不确定它是否安全。

4 个答案:

答案 0 :(得分:4)

  

1。关于使用eval从字符串创建排序函数是否存在任何问题?

本身并不存在,但它确实遇到与使用字符串调用其他eval样式函数相同的缺陷,例如: setTimeout()Function()构造函数。只要您信任字符串的来源,就没有真正的问题。但是,我会考虑使用Function构造函数:

f = new Function(a, b, ai, bi, e, 'return ' + func);

它更易于管理,它肯定比评估函数声明更合适。

  

2。是否有关于排序函数返回-1(nagative),0和1(正)的故事?

并不是真正理解你问题的这一部分,但如果比较中两个项目相同,那么你的功能似乎无法解决该怎么做。根据结果​​,您应该返回小于0,0或大于0的值。最好的方法是使用String.prototype.localeCompare()

return String.prototype.localeCompare.call(a, b);

答案 1 :(得分:0)

尝试制作它,这样你只需要在一小部分上进行评估:

(小提琴:http://jsfiddle.net/maniator/SpJbN/

function sortBy(obj, extra, func){
    var f = null;
    if(typeof func == 'function'){
        f = func;
    } else if(typeof extra != 'function'){
        f = function(a, b, ai, bi, e){
            return eval(func); // <-- smaller part
        }
    } else {
        f = extra;
        extra = null;
    }

    var res = [];
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
            obj[i]._k_ = i;
            res.push(obj[i]);
        }
    }

    res.sort(function(a, b){
        if(f(a, b, a._k_, b._k_, extra)){
            return 1;
        } else {
            return -1;
        }
    })

    return res;
}

答案 2 :(得分:0)

  1. 感谢Andy,我们将代码更改为

    var f = new Function('a,b,ai,bi,e','return'+ func);

  2. 请注意,参数应该以字符串形式传递,请检查: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function

    1. 关于第二个问题,我认为这是因为我们试图更明确地进行排序功能。 例如,

      排序([1,2,3,5,1],'','a&lt; b')==&gt; [1,1,2,3,5]

    2. 'a&lt;的字面含义b'对我们来说是“后一项大于前一项”,因此数组被排序为[1,1,2,3,5]。

      另一个例子,'a.age&lt; b.age'将按照年轻人在奥尔德斯之前的顺序返回记录。

      这就是我问的原因,我们可以使用真或假而不是-1,0,1。

      我们继续做一些小测试,想出一些东西,想与大家分享。

      例如:

      var b = [
          {age:27, name:'pop 2', role: 'Programmer'},
          {age:19, name:'james', role: 'Accontant'},
          {age:19, name:'jerry', role:'Sales Representative'},
          {age:22, name:'jerry', role:'Coder'},
          {age:19, name:'jerry', role:'Tester'},
          {age:14, name:'anna', role: 'Manager'},
          {age:19, name:'luke', role:'Analyst'},
          {age:27, name:'pop', role: 'Programmer'},
          {age:14, name:'anna 2', role: 'Manager'}
      ];
      
      b.sort(function(a, b) {return a.age - b.age > 0? 1: -1}); // #1
      b.sort(function(a, b) {return a.age > b.age});  // #2
      b.sort(function(a, b) {return a.age - b.age});  // #3
      

      虽然上述排序返回相同的结果,但请尝试以下方法:

      b.sort(function(a, b) {return a.age - b.age < 0? -1: 1});  // #4
      

      在此声明中,记录仍按年龄排序,但订单在同一年龄段内被撤销。

      #1和#2偶然与#3相同。如果浏览器使用不同的算法来实现排序功能, #1和#2的行为可能与#4相似。如果您严格按照结果的顺序,则需要 当'a'等于项'b'时显式返回0。

      此外,正如Andy指出的那样,在某些情况下(例如#4),如果我们没有明确地返回0,则可能会进行不必要的交换,这可能会影响性能。

      之前我们没有注意到这一点的原因是因为我们不关心组内的顺序,提供记录 按特定属性排序。

答案 3 :(得分:-1)

我认为传递一个进行比较的函数是合适的。像

这样的东西
sort(somedata, function(a, b) {
    return a < b;
});