2011-06-22 59 views
5

背景排序功能:關於JavaScript的

根據需要在某些任務,我需要一個簡單的排序功能。爲簡單起見,我寫了另一個功能包內置的排序功能:

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. 允許一些簡單的語法

例如,

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從字符串創建排序函數的任何potiential問題?
  2. 有沒有關於排序函數返回-1(負數),0和1(正數)的故事? 我們是否可以將代碼更改爲「return if(f(a,b,a。k,b。k,extra)」,而不是返回1或-1?我們發現它適用於我們的firefox和chrome ,但不能確定它是否是安全的這樣做。
+2

爲什麼不使用已存在的排序函數? – dave

+0

@dave他是:「我編寫了另一個函數來將*內置的排序函數*包裝爲...「 –

+0

如果我不記得錯誤的排序函數只是針對Array對象的,對吧? –

回答

0
  1. 感謝Andy,我們修改代碼,

    變種F =新功能( 'A,B,AI,BI,E' ,'return'+ func);

注意,參數應該爲字符串傳遞中,檢查出: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function

  1. 關於第二個問題,我想這是因爲我們試圖使排序功能更加明確。 例如,

    排序([1,2,3,5,1], '', '一個< B')==> [1,1,2,3,5]

'a < b'給我們的字面意思是「後一項大於前一項」,所以數組排序爲[1,1,2,3,5]。

另一個例子,'a.age < 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,可能會影響性能,從而導致不必要的交換。

之前我們沒有注意到這個原因是因爲我們並不關心組內的訂單,提供的記錄 是按特定屬性排序的。

+1

我應該在回答中指出的一點是性能,如果一個項目不需要移動,應該返回'0',因爲不需要做任何事情。一個已經排序爲'[1,1,1,5,3,4]'的數組儘管前三個條目已經到位,但你仍然在告訴排序實現來移動它們,因此需要更多的工作要做。 –

+0

謝謝你,你提出了一個好點 –

+0

我認爲這取決於瀏覽器如何實現排序功能。例如,在#1和#2的聲明中,我認爲性能不同於#3(標準的),因爲排序的項目保持原始順序,是嗎?當然,在#4中,它需要額外的工作。 –

-1

我想通過這確實比較。所以像

sort(somedata, function(a, b) { 
    return a < b; 
}); 
+2

這已經在代碼中了...... – Neal

0

試着做,所以你只能做一個功能,這將是適當的eval的一小部分:

(小提琴: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; 
} 
+1

從技術上講,在你的版本中,每次調用排序函數時都會調用編譯器,在這兩種情況下,'f = new Function(...)'都會更合適 –

4

1.是否有關於使用eval創建一個從字符串排序功能的任何項目後備問題?

不是本身,但它確實遭受與使用字符串調用其他eval樣式函數的所有相同的缺陷,例如, setTimeout()Function()構造函數。只要您信任字符串的來源,就不存在真正的問題。不過,我會考慮使用Function構造來代替:

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

它更易於管理,它是絕對比評估函數聲明更合適。

2.是否有關於返回-1(負數),0和1(正數)的排序函數的任何故事?

不是真正理解這個部分的問題,但是你的函數似乎沒有處理如果兩個項目在比較中相同時應該怎麼做。根據結果​​,您應該返回小於0,0或大於0。對於這一點,最好的方法是使用String.prototype.localeCompare()

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

感謝第一個回答這是一個很好的建議 –

+0

+1爲答案 –