[英]About a sort function for 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;
}
我的尝试是:
例如,
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从字符串创建排序函数是否存在任何问题?
本身不是,但它确实遇到与使用字符串调用其他eval样式函数相同的缺陷,例如setTimeout()
或Function()
构造函数。 只要您信任字符串的来源,就没有真正的问题。 但是,我会考虑使用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);
尝试制作它,这样你只需要在一小部分上做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;
}
感谢Andy,我们将代码更改为
var f = new Function('a,b,ai,bi,e','return'+ func);
请注意,参数应该作为字符串传递,请查看: https : //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
关于第二个问题,我认为这是因为我们试图更明确地进行排序功能。 例如,
排序([1,2,3,5,1],'','a <b')==> [1,1,2,3,5]
对我们来说'a <b'的字面含义是“后一项比前项更大”,因此数组被排序为[1,1,2,3,5]。
另一个例子,'a.age <b.age'将按照年轻人在olders之前的顺序返回记录。
这就是我要求的原因我们可以使用真或假而不是-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,则可能会进行不必要的交换,这可能会影响性能。
我们之前没有注意到这一点的原因是因为我们不关心组内的顺序,只要记录按特定属性排序。
我认为传递一个进行比较的函数是合适的。 所以像
sort(somedata, function(a, b) {
return a < b;
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.