【转载】JavaScript 学习笔记:数组的 sort() 和 reverse() 方法

!转载链接:https://www.w3cplus.com/javascript/array-part-4.html

!!仅供学习,若有侵权,立刻删除!!



在实际的业务当中,很多时候要对定义好的数组重新排序。在 JavaScript 中自带了两个方法,可以对数组进行排序操作。这两个方法就是sort()reverse()。今天就来学习这两个方法相关的知识。

sort()方法

sort()方法对数组的元素做原地的排序,并返回这个数组。默认情况下,sort()方法是按升序排列数组项。即最小的值位于最前面,最大的值排列在最后面。为了实现排序,sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串,以确定如何排序。

先来看一个简单的示例:

<pre class="hljs ruby">var arr = ['hello','jame','Jack','dog']; // 定义一个数组
console.log(arr.sort()); // ["Jack", "dog", "hello", "jame"]</pre>

正如前面所言,sort()方法未调用任何参数时,是按升序排列的,也就是按字母的顺序排列,所以我们看到结果也是正确的。

接下来,再看一个数字的数组排列的示例:

<pre class="hljs javascript">var arr = [1,5,10,22]; // 定义一个数组
console.log(arr.sort()); // [1, 10, 22, 5]</pre>

可见,即使示例中数组的顺序没有任何问题,但sort()方法对数组进行重新排序操作之后,顺序反而不对了。这究竟是为何呢?

查了相关文档才知道,sort()方法:如果省略参数,数组项会先根据toString()函数将其值转换成字符串在进行比较,是按 UNICODE 进行比较的,然后根据这个进行排序。正如最前面的示例,"Jack" 会排在 "dog" 前面。当数字进行排序的时候,"5" 会出现在 "10" 和 "22" 之后,因为他们先会被转换为字符串,而 “10” 和“22”都比 “5” 要靠前。

我们可以使用charCodeAt()来验证一下:

<pre class="hljs coffeescript">"Jack".charCodeAt() ==> 74
"dog".charCodeAt() ==> 100
"5".charCodeAt() ==> 53
"10".charCodeAt() ==> 49
"22".charCodeAt() ==> 50</pre>

如此一来,这不是最佳方案。幸好,sort()方法可以接受一个比较函数compareFunction作为参数,以便我们指定哪个值位于哪个值的前面。

如果指明了compareFunction,那么数组会按照调用该函数的返回值进行排序。比较函数compareFunction接收两个参数abab是两个将要被比较的元素:

  • compareFunction(a,b)返回的值小于0:那么a就小于b,也就是说a排在了b的前面
  • compareFunction(a,b)返回的值大于0: 那么a就大于b,也就是说a排在了b的后面
  • compareFunction(a,b)返回的值等于0:那么a就等于b,也就是说ab的位置保持不变

compareFunction(a,b)函数:

<pre class="hljs javascript">function compareFunction (a, b) {
if (a < b) {
return -1; // a排在b的前面
} else if (a > b) {
return 1; // a排在b的后面
} else {
return 0; // a和b的位置保持不变
}
}</pre>

这个函数可适用于大多数数据类型,只要将compareFunction(a,b)函数作为参数传给sort()方法即可。因到前面的示例:

<pre class="hljs javascript">var arr = [1,5,10,22]; // 定义一个数组
arr.sort(compareFunction); // 将compareFunction函数作为参数传给 sort()
console.log(arr); // [1, 5, 10, 22]</pre>

数组arr仍然保持了正确的升序排列。其实可以通过compareFunction(a,b)对数组作降序排列,只需要将compareFunction函数的返回值做个调整即可:

<pre class="hljs javascript">function compareFunction (a, b){
if (a < b) {
return 1; // a排在b的后面
} else if (a > b) {
return -1; // a排在b的前面
} else {
return 0; // a 和 b 保持位置不变
}
}

var arr = [1, 5, 10, 22]; //定义一个数组
arr.sort(compareFunction); // 将compareFunction函数作为参数传给sort()
console.log(arr); // [22, 10, 5, 1]</pre>

注:compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。

上面也说到了,sort()方法传入compareFunction(a,b)参数时,返回的值可能有3个,所以下面这样的写法是错误的:

<pre class="hljs javascript">function compareFunction (a, b) {
return a < b;
}

var arr = [21, 0, 3, 11, 4, 5, 6, 7, 8, 9, 10];
arr.sort(compareFunction);
console.log(arr); // [5, 21, 11, 10, 9, 8, 7, 6, 4, 3, 0]</pre>

可能得的结果是 [5, 21, 11, 10, 9, 8, 7, 6, 4, 3, 0],这并不是正确的结果,那是因为return a < b只返回了两种值 truefalse,相当于10,而没有-1

对于数字类型或valueOf()方法返回数值类型的对象类型,可以使用一个更简单的比较函数。

<pre class="hljs javascript">// ascSort(a,b)传给sort(),数字数组作升序排列
function ascSort (a, b) { // a和b是数组中相邻的两个数组项
return a - b;
// 如果 return -1, 表示a小于b,a排列在b的前面
// 如果 return 1, 表示a大于b,a排列在b的后面
// 如果 return 0, 表示a等于b,a和b的位置保持不变
}

// desSort(a,b)传给sort(),数字数组作降序排列
function desSort (a, b) { // a和b是数组中相邻的两个数组项
return b - a;
// 如果 return -1, 表示b小于a,b排列在a的前面
// 如果 return 1, 表示b大于a, b排列在a的后面
// 如果 return 0, 表示 b等于a, b和a的位置保持不变
}</pre>

来看看结果是不是我们想要的结果:

<pre class="hljs javascript">var arr = [1,4,10,3],
arr2 = [100,12,99,3,2]; //定义数组
arr.sort(ascSort); // 将ascSort函数传给sort()
arr2.sort(desSort); // 将desSort函数传给sort()
console.log(arr); // [1, 3, 4, 10]
console.log(arr2); // [100, 99, 12, 3, 2]</pre>

字符数组排列

创建一个字符串数组,并且使用sort()对字符串进行重新排序:

<pre class="hljs javascript">var stringArray = ['blue', 'Humpback', 'Beluga'];
stringArray.sort();
console.log('字符串数组stringArray:' + stringArray);</pre>

Chrome 输出的结果:

<pre class="hljs css">字符串数组stringArray:Beluga,Humpback,blue</pre>

数字字符串数组排列

创建一个数字字符串数组之后对数组进行排序,对比数字数组分别指定与不指定比较函数的结果:

<pre class="hljs javascript">var numericStringArray = ['80', '9', '700'];

function compareFunction (a, b) {
return a - b;
}

console.log('不指定比较函数的数字字符串数组排列:' + numericStringArray.sort());
console.log('指定比较函数的数字字符串数组排列:' + numericStringArray.sort(compareFunction));</pre>

Chrome 输出的结果:

<pre class="hljs">不指定比较函数的数字字符串数组排列:700,80,9
指定比较函数的数字字符串数组排列:9,80,700</pre>

数字数组排列

创建一个数字数组之后对数组进行排序,对比数字数组分别指定与不指定比较函数的结果:

<pre class="hljs javascript">var numberArray = [80, 9, 700];

function compareFunction (a, b) {
return a - b;
}

console.log('不指定比较函数的数字数组排列:' + numberArray.sort());
console.log('指定比较函数的数字数组排列:' + numberArray.sort(compareFunction));</pre>

Chrome 输出的结果:

<pre class="hljs">不指定比较函数的数字字符串数组排列:700,80,9
指定比较函数的数字字符串数组排列:9,80,700</pre>

数字和数字字符串混合数组排列

创建一个数字和数字字符串混合数组之后进行排序,对比数组分别指定与不指定比较函数的结果:

<pre class="hljs javascript">var mixedNumericArray = ['80', '9', '700', 40, 1, 5, 200];

function compareFunction (a, b){
return a - b;
}

console.log('不指定比较函数的数组排列:' + mixedNumericArray.sort());
console.log('指定比较函数的数组排列' + mixedNumericArray.sort(compareFunction));</pre>

Chrome 输出的结果:

<pre class="hljs">不指定比较函数的数组排列:1,200,40,5,700,80,9
指定比较函数的数组排列1,5,9,40,80,200,700</pre>

数字数组随机排列

除了给数字数组进行升序或降序排列之外,还可以定义一个随机函数,实现数组的随机排列。定义的随机函数返回正数或者负数,并表将随机函数传给sort()方法,此时sort()方法根据随机函数返回的正负数来决定两个值之前的位置。

<pre class="hljs javascript">var randomArray = [9,0,23,8,3,5];

function randomSort(a, b) {
return Math.random() - 0.5;
}

console.log(randomArray.sort(randomSort));
// [8, 5, 9, 0, 23, 3]
// [8, 3, 5, 0, 23, 9]
// [8, 5, 0, 3, 9, 23]</pre>

对象数组排列

对于对象数组排列,我们同样需要先写一个构造函数:

<pre class="hljs javascript">function objectSort(property, desc) {
//降序排列
if (desc) {
return function (a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
}
return function (a, b) {
return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
}
}

var myArray = [
{ "name": "John Doe", "age": 29 },
{ "name": "Anna Smith", "age": 24 },
{ "name": "Peter Jones", "age": 39 }
]

console.log(myArray.sort(objectSort('name',true))); // 按object中的name的降序排列</pre>

来看看 Chrome 输出的前后结果:

image

另外,只需要改变比较函数objectSort()中的desc参数值为flase,数组就会按object指定的property属性降序排列:

<pre class="hljs javascript">console.log(myArray.sort(objectSort('age',false))); //按objcet中的age升序排列</pre>

Chrome 输出的前后结果:

image

除此之外,还有其的对比较函数,如下所示:

<pre class="hljs javascript">function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
console.log(myArray.sort(dynamicSort('age'))); // 按升序排列
console.log(myArray.sort(dynamicSort('-age'))); // 按降序排列</pre>

上面介绍的是按一个属性进行排序,但很多时候,希望按多个属性排序,那么比较函数需要做一定的调整:

<pre class="hljs javascript">function dynamicSortMultiple() {
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}

myArray.sort(dynamicSortMultiple('name','-age'));</pre>

reverse()方法

reverse()方法相对而言要简单得多,它就是用来颠倒数组中元素的位置,并返回该数组的引用。比如我们有一个数组:

<pre class="hljs coffeescript">var myArray = ["Airen","W3cplus","Blog"];
console.log(myArray.reverse()); // ["Blog", "W3cplus", "Airen"]</pre>

总结

本文主要介绍了数组中元素项的排序方法。而主要详细介绍的是sort()方法。通过给sort()方法传递不同的比较函数,我们可以实现字符串数组数字数组数字和数字字符串混合数组对象数组等按顺序 (升序降序) 排列。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容