js前端开发 需要Array#sort方法

前端开发用js数组吗?|前端开发未来趋势演讲视频|前端项目开发工具
不全看也行,要注意最后的“前方高能”那块。

先说说为啥要写这篇文章。
很多初学者,基本上初遇到sort方法时,都感觉困惑,因为要写一个函数作为参数,作为比较器。
而大多数书籍上介绍此方法时,最多就举一下数字升序和逆序的例子就拉倒了。比如《高设》和犀牛书。
而上网去找相关资料时,那种什么array.sort详细或彻底研究之类的文章,我看了几篇,根本一点也不详细也不彻底。
当然了,我也只是看前几篇而已。纵然不能一棍子打死,对吧。省着别人说你,“小样儿,这么嚣张,欠扁是吧?”,是不?
今天我也来写一篇,再多举几个例子。

正文开始

首先要了解的事情是:如果不传参数时,是按照什么顺序来排列的?
字母顺序!!
[quote]var arr = [‘c’, ‘b’, ‘a’, ‘abc’, ‘aba’, ‘aa’];
arr.sort();
console.log(arr);
//=>[“a”, “aa”, “aba”, “abc”, “b”, “c”][/quote]
从上面可以看出,
sort方法会改变原先数组。
sort方法无参数时确实是按照字母顺序来排序的。
你看其他文章时,人家说的是“更精确说法是按照字符编码的顺序进行排序”。
且看下面例子
[quote]var arr = [‘a’, ‘x’, 0, false, ‘b’, ”, ‘ ‘, 2, ‘1’, [], {toString:function(){return ‘a’}}, ‘老姚’, function(){}];
arr.sort();
console.log(arr);
//=>[Array[0], “”, ” “, 0, “1”, 2, “a”, Object, “b”, false, function, “x”, “老姚”][/quote]
当然上面的例子是我瞎举的,谁闲着没事儿会这么去给这些东西排序?
看上面的例子的结果,看到了那个{toString:function(){return ‘a’}}是排在a后面的吗?
说明一个问题,按字母顺序来排序时,不是字符串时,会转化为字符串的。
无参数时,我们就记住是按照字母来排序的,就可以了。
正因为按照字母来排序的,即使数字也不会按照大小排序的。
[quote]var arr = [8, 1, 3, -1, 22, +9, -22, -223, +89, 10, 0, 1.2];
arr.sort();
console.log(arr);
//=>[-1, -22, -223, 0, 1, 1.2, 10, 22, 3, 8, 89, 9][/quote]
打印结果我是从chrome控制台上copy的。大家都知道,想要按照数字大小来排序的话,必须要用比较器了。

我们就首先研究一下比较器。
先不写任何返回值
[quote]var arr = [5, 4, 3, 2, 1];
arr.sort(function(){
console.log(arguments);
});
console.log(arr);
//=>[5, 4]

//=>[4, 3]

//=>[3, 2]

//=>[2, 1]

//=>[5, 4, 3, 2, 1][/quote]
从上面可以看出,比较器是传进两个参数的。
就这个例子而言,arr没有变化,并且比较器运行了4次。

到底是怎么比较的呢?
排序排序嘛,必须得有一种排序的规则嘛。
也就是说通过这种规则,要给出一种关系(顺序关系),对于任意给出两个元素a和b,都能唯一确定是如下其中一种情况:
a必须排在b之前
a必须排在b之后
a和b是同等地位的,谁前谁后无所谓。

其实就是一种升序,对应的关系就是广义的小于等于关系(说完这段话,我想起了数学课程里的抽象代数)。
上面为啥说是广义呢,数字的大于等于关系其实就是上面说的那种“广义的小于等于关系”。
有点绕,如果改成“前后关系”就没问题了吧。

为了方便说下去,还是举一下那个喜闻乐见的例子。数字升序。
[quote]var arr = [1, 4, 3, 2, 5];
arr.sort(function(a, b){
console.log(arr)
console.log(arguments)
if (a > b) {
return 1;
} else if (a < b) {
return -1;
}
return 0;
});
console.log(arr);[/quote]
先不看打印,先看看程序里怎么确定这个关系。
看到上面那三个return了吗,就是告诉sort具体排序规则。
a和b分别是数组的中元素。
如果比较器返回一个负数,就认为a在b之前,
如果比较器返回一个正数,就认为a在b之后,
如果比较器返回0,就认为二者谁前谁后应该没关系(非稳定的,不一定按照原先顺序)。

具体排序过程又是如何呢?
这里先贴一下上述例子console(chrome)的结果
[quote]//=>[1, 4, 3, 2, 5]

//=>[1, 4]

//=>[1, 4, 3, 2, 5]

//=>[4, 3]

//=>[1, 4, 4, 2, 5]

//=>[1, 3]

//=>[1, 3, 4, 2, 5]

//=>[4, 2]

//=>[1, 3, 4, 4, 5]

//=>[3, 2]

//=>[1, 3, 3, 4, 5]

//=>[1, 2]

//=>[1, 2, 3, 4, 5]

//=>[4, 5]

//=>[1, 2, 3, 4, 5][/quote]
最后的一条打印是arr的最终结果。
从上面可以看出,比较器(函数参数)总共执行了7次。
总体可以看出arr是在不断变化中。
a和b是数组中两个具体的元素。
chrome的具体内部采用的排序方法,到底是什么,怪我眼拙,没有看出来,数据结构早忘了。
你可以看ECMA-262规格(规范)文件对sort方法的介绍。
我大致看了一下,里面果然出现了“等价类”的概念。好吧,得问候一下抽象代数老师。
具体内部采用什么排序方法,可以看看规格文件。各大浏览器是不是那么实现的,不清楚。

然而,然而,内部实现我们并不关心!!
我们关心的是如何给出各种各样的比较器,用以实现各种各样的排序。
ok,原理这东西就到此为止。

下面整几个例子。。。
实现自定义的排序的关键就是要给出比较器。

假如函数不写返回值
[quote]var o = {
toString: function() {
return ‘y’;
}
};
var arr = [‘x’, 1, 4, ‘y’, 3, 2, o, 5];
arr.sort( function(a, b){} );
console.log(arr);
//=>[“x”, 1, 4, “y”, 3, 2, Object, 5][/quote]
可以看出,位置没有变化,
不写返回值时,相当于return undefined,
内部转化为-1了。注意不是按照字母来排序的。

返回值只要是正负即可,不一定是1,-1。写42和-5也行。
例如直接返回负数,相当于没排序。
[quote]var arr = [1, 4, 2, 5, 3];
arr.sort(function(a, b){
return -2;
});
console.log(arr);
//=>[1, 4, 2, 5, 3][/quote]
如果返回一个正数呢?
[quote]var arr = [1, 4, 2, 5, 3];
arr.sort(function(a, b){
return 42;
});
console.log(arr);
//=>[3, 5, 2, 4, 1][/quote]
上面这个例子是reverse的实现。不管a和b具体是什么样的,始终认为a在b之后。

要根据a和b的特点来排序的话,我们得要用到a和b具体情况,来给出排序规则。
比如,我们常见数字升序的实现如下
[quote]var arr = [5, 4, 3, 2, 1];
arr.sort(function(a, b){
return a – b;
});
console.log(arr);
//=>[1, 2, 3, 4, 5][/quote]
降序可以改成return b – a;

再比如我要根据元素的长度来排序
[quote]var arr = [‘xxxx’, ‘xx’, ‘xxx’, ‘yyyy’, ‘zzz’, ‘w’];
arr.sort(function(a, b){
return a.length – b.length;
});
console.log(arr);
//=>[“w”, “xx”, “xxx”, “zzz”, “xxxx”, “yyyy”][/quote]

再比如我要以优先按长度排,然后按照字母顺序排,也可以实现的。
[quote]var arr = [‘abcd’, ‘abc’, ‘bbb’, ‘aaa’, ‘ba’, ‘ab’];
arr.sort(function(a, b){
if (a.length === b.length) {
for (var i = 0; i < a.length; i++) {
if (a.charCodeAt(i) !== b.charCodeAt(i)) {
return a.charCodeAt(i) – b.charCodeAt(i);
}
}
}
return a.length – b.length;
});
console.log(arr);[/quote]

同样的,我要按照特定字母来排序,比如b开头的字母要排在前面。其他的就按照原顺序来排。
[quote]var arr = [‘abcd’, ‘abc’, ‘bbb’, ‘aaa’, ‘ba’, ‘ab’];
arr.sort(function(a, b){
if (a[0] === ‘b’) {
return – 1;
}
if (b[0] === ‘b’) {
return 1;
}
return -1;
});
console.log(arr);
//=>[“bbb”, “ba”, “abcd”, “abc”, “aaa”, “ab”][/quote]

在比如我要按照对象的某一属性来排序呢?
如下例子先安装年龄来排序,如果年龄相同,再按名字字母来排序。
[quote]var list = [ {name:’xxx’, age:20}, {name:’yyy’, age:25}, {name:’zzz’, age: 18}, {name:’aaa’, age:20}];
list.sort(function(a, b){
if(a.age === b.age) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
//可以少些个if,这是字母排序的另一种实现
}
return a.age – b.age;
})
console.log(list);
//=>如你所料[/quote]

例子可以随便举的。现在你也能做到举一反n了吧。
关于稀疏数组的例子,这里没有举,你可以试试。

本文写到这里,看似差不多讲完了。
如果真讲完了,那就不是老姚写的文章!!

前方高能!!

上面的比较器都是写成匿名函数的,很难让人一眼看出,具体含义
因为比较器,需要给出3种返回值,不是很语义化。
我们希望的是什么呢?最好传个谓词函数能实现那是最好的。
什么是谓词函数呢?就是返回boolean值的函数。谓语嘛!“是不是”的意思嘛。
比如
[quote]function lessThan(a, b) {
return a < b;
}[/quote]
lessThan这个函数就是谓词函数,判断a是否小于b。
我们当然希望传入sort方法时,最好是这种的函数。
让人一看就是小于关系,一看就是升序。
sort需要的一个比较器,比较器嘛,是三种情况。而谓词函数只有两种情况。
天下没有免费的午餐。
所以我们得稍微费点事请。来实现这种转换。当然是一劳永逸的。
[quote]function comparator(pred) {
return function(x, y) {
if(pred(x, y)) return -1;
if(pred(y, x)) return 1;
return 0;
};
}[/quote]
具体使用呢?
例如,

[5, 4, 3, 2, 1].sort(comparator(lessThan));
这么做的好处就是我们一眼就能看出我们的排序规则是“是否是按小于关系来排序的”,那当然是升序了。
再比如我想安装是否是偶数来排序(偶数排在前面,奇数排在后面)
注意我这里只用了一个形参,就够了。
[quote]function isEven(a) {
return a % 2 == 0;
}[/quote]
使用如下

[5, 4, 3, 2, 1].sort(comparator(isEven));
这回看到了此种方式的实现好处了吗。
记得之前那个先按照年龄然后再按照姓名字母排序规则那个例子嘛?
我可以创建好多规则
比如
[quote]function nameGreatThan(p1, p2) {
return p1.name > p2.name;
}
function ageLessThan(p1, p2) {
return p1.age < p2.age
}[/quote]
按照name字母降序来排列

list.sort(comparator(nameGreatThan))
按照年龄大小升序来排列

list.sort(comparator(ageLessThan))
混合排列呢?

list.sort(comparator(costomOrder))
costomOrder如何来实现呢?注意我们需要他是个谓词函数!
[quote]function costomOrder(p1, p2) {
if(p1.age === p2.age) return nameGreatThan.apply(this, arguments);
return ageLessThan.apply(this, arguments);
}[/quote]

哈哈是不是清爽了很多!!
本文完。

web前端的开发工具有那几个?|web前端开发工具比较|现在web前端怎么开发工具

» 本文来自:前端开发者 » 《js前端开发 需要Array#sort方法》
» 本文链接地址:https://www.rokub.com/3946.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!