Go to comments

JavaScript 数组常用方法

ECMAScript3.0 是最标准的方法,之前学过的一系列东西,包括之后学的一系列东西都是基于es3.0,es3.0是最基础、最全面,最强大的一个通式版本,


ES5.0 是在 ES3.0 的基础上加了几个新方法而已,还并不是所有浏览器都好使,新版本浏览器支持ES5.0,老版本浏览器还没升级到ES5.0(比如老版本IE)。


ES6.0 是在 3.0、5.0 的基础上又提出的一些新方法,ES6.0是一个强大、飘逸的版本,现在学的是 es3.0 包含 es5.0 的(有些方法就不区分es3和es5了),


本次数组的方法都是 ES3.0 的方法,ES3.0 数组的方法是数组最重要的一些方法,然后把 es3.0 的方法分为两类,一种是可以改变原数组的一类,一种是不可以改变原数组的一类,按照这个分类学。


数组常用的方法

改变原数组 push, pop, shift, unshift, sort, reversem, splice

不改变原数组 concat, join —> split, toString, slice


一、可以改变数组的方法

这些方法都是可以改变原数组的,意思是在原数组的基础上去改变,添加或者剪切

方法名作用用法
push()在数组最后一位添加

var arr = [1,2,3];

arr.push(4);

console.log(arr); // [1, 2, 3, 4]

pop()从最后一位减去(删除)
unshift()在数组前面添加,和push方法相反
shift()从数组前面减

var arr = [1,2,3];

arr.shift();

console.log(arr); // [2, 3]

reverse()反排数组
splise()截取,在截取处插入
sort()排序


1. push()

数组是引用值,是可以访问方法的,push方法是数组自己的不是什么包装类的

1 . push是往数组添加数据的方法,添加任何类型的数据都可以

2. 在哪添加数据?在数组的最后一位添加数据

var arr = [];

console.log(arr.push(10)); // push是往数组里面放东西的,默认返回到是数组的长度"1",原来数组的长度是0
console.log(arr); // [10]

console.log(arr.push(11)); // 再调用数组push一个11进去,默认返回数组长度是2
console.log(arr); // [10, 11]

console.log(arr.push(9)); // 再push一个9进去,数组长度默认返回3
console.log(arr); // [10, 11, 9]


push方法还可以同时添加多个,怎么添加都行,这个方法特别的强大

var arr = [10, 11, 9];

arr.push(1,2,3,4,5,6,7); // 7

console.log(arr); // [10, 11, 9, 1, 2, 3, 4, 5, 6, 7]


我们自己写一个push方法,看看能不能覆盖系统的

1. push方法在Array原型上  Array.prototype.push

2. 调用push能打印出"哈哈",说明可以覆盖系统的

var arr = [];

Array.prototype.push = function(){
  return "哈哈";
}

console.log(arr.push()); // 哈哈


在这个基础上重写一个 myPush 方法

1. 重写的push不能写形参,因为不知道要传多少位,所以只能用 arguments

2. push方法是把数据,放到数组的最后一位,怎么放到最后一位呢?

Array.prototype.myPush = function(){

  for(var i = 0; arguments.length > i; i++){
    // console.log(i, this.length);
    this[this.length] = arguments[i];
  }

  return this.length;
}


var arr = ['1origin' ,'2origin'];

console.log(arr.myPush(3,4,5,6)); // 6

console.log(arr); // ["1origin", "2origin", 3, 4, 5, 6]


思路:

比如数组  arr = [1,2]  里面已经有两位了,现在push一个数字3进去,3的位置应该在数组的最后一位

1. 数组从0位、1位开始算,数组的长度是的2

2. 长度2可以代表数组中有三位 0位,1位, 2位

3. push这个3应该在数组最后一位,而长度2表示数组的最后一位, arr[2]  中括号里的2是push进去3后数组的长度arr.length

4. 接下来再在给数组 arr = [1,2,3] 加一个4,arr[3] 中括号里面填的3,就是要往数组里面push的位置(最后一位)

所以,就是往数组第length位上填东西,因为length位还没出生呢,数组的最后一位永远是 length - 1 


实现方式:

1. 把arguments遍历一下,把arguments里面的每一个东西都拿出来,

2. 数组不存在时原型链就存在了,原型链上的方法不知道今后是谁会去调用,不知道谁调用拿this代替, this[this.length] 谁调用它谁是this,

下次循环的时候this.length的长度自动就加1了,不用我们自己加加,数组就有这个特性

和系统自带的push一样,最后把数组的长度返回 return this.length


为什么写这个方法呢?

一方面启发下思路看系统怎么来实现的,另一方面以后要学会在原型链上编程。


什么叫在原型链上编程?

在原型链上写咱们通用的方法,

比如数组去重,去重方法数组没给咱们提供,咱们需要写到原型链上,让以后所有的数组都可以实现这个方法。


2. pop()

pop方法说删除不标准,先看效果

var arr = [1,2,3];


console.log(arr.pop()); // 返回3
console.log(arr); // 数组剩下[1, 2]


console.log(arr.pop()); // 返回2
console.log(arr); // arr数组变成[1]

pop方法把数组的最后一位,不叫删除叫剪切出去,是把数组的最后一位剪切出去


变量num的值是3,变量num是数组最后一位剪切出来的那个数

var arr = [1,2,3];

var num = arr.pop();

console.log(num); // 3

console.log(arr); // [1, 2]


pop在执行的时候不用传参,传了也白传

var arr = [1,2,3];

arr.pop(2); // 想剪切两位

console.log(arr); // [1, 2] 数组只剪切最后一个,传的参数被忽略


总结

pop就是从最后一位去剪切,

push就是从最后一位去增加,

它俩是相反的


3. unshift()

shift 键盘上有这个键,unshift 方法别看加 un 了,但是 unshift 方法是添加东西的


比如给数组增加一个 0,unshift 是在数组的前面加东西,和 push 方向是相反的

var arr = [1,2,3];

arr.unshift(0); // 返回数组的长度 4

console.log(arr); // [0, 1, 2, 3]


unshift 是增加而且是在数组前面增加,那 shift 是从前面减

var arr = [1,2,3];

arr.shift(); // 1

console.log(arr); // [2, 3]


看看 unshift 能不能像 push 一样那么飘逸,加两个进去!

var arr = [1,2,3];

arr.unshift(-1, 0); // 返回数组长度 5

console.log(arr); // 数组变成 [-1, 0, 1, 2, 3]

unshift 方法能加两个进去


unshift 像 push 一样重写,怎么写?

先考虑插入的问题,看一个问题,数组能不能在它的 -1 负一位里面放东西?

var arr = [1,2,3];

arr[-1] = 0;

console.log(arr); // [1, 2, 3, -1: 0]

没用,不能这么往前插东西


怎么办?

定义一个新的数组,然后把两个数组拼到一起就可以了,而且数组还有拼接方法叫 concat


不用 concat 方法,把参数当成一个新的数组,然后把原数组 push 到这个数组里就可以了,正好把原数组插入到新数组后面

Array.prototype.MyUnshift = function(newArr){

  var valArr = []; // 内部新建数组

  // 把argments挨个赋值给内部新数组valArr
  for(var i = 0; arguments.length > i; i++){
    valArr[i] = arguments[i];
  }

  // 把老数组(this) push给新valArr
  for(var i = 0; this.length > i; i++){
    valArr.push(this[i]);
  }

  // valArr已经是"参数新数组"在前,老数组this在后,
  // 再把valArr重新覆盖老数组this,完成改变原数组。
  for(var i = 0; valArr.length > i; i++){
    this[i] = valArr[i];
  }

  return this.length;

}

var arr = ["a",2,3];
console.log(arr.MyUnshift(5,6,"中文")); // 6
console.log(arr); // [5, 6, "中文", "a", 2, 3]


4. shift()

unshift 在数组前面增加,shift 方法从数组前面减

var arr = [1,2,3];

arr.shift(); // 1
console.log(arr); // [2, 3]


arr.shift(); // 2
arr.shift(); // 3
arr.shift(); // undefined


5. reverse()

reverse 是逆反的意思,reverse() 方法逆转顺序后,它把原数组返回来,reverse 不是返回新数组,改变的是原数组

var arr = [1,2,3];


console.log(arr.reverse()); // [3, 2, 1]

console.log(arr.reverse()); // [1, 2, 3]

console.log(arr); // [1, 2, 3]


6. splice()

splice 方法是除 sort 以外相对复杂的一个方法了,而且它的应用非常多,splice 是切片的意思


splice( 从第几位开始,截取多少的长度,在切口处添加新的数据 )

方法难就难在传参上,里面传了好些个参数


先看截取的功能不看切的

从第一位开始截取,截取两位

1. arr.splice( 1, 2 ) 从第一位开始,应该包含第一位截取两位

2. [1, 1, 2, 2, 3, 3]  返回的是截取的部分 [1, 2] 

var arr = [1, 1, 2, 2, 3, 3];

arr.splice(1,2); // 返回截取部分 [1, 2]

console.log(arr); // 再打印原数组剩下[1, 2, 3, 3]

3. 换句话说截取也是一种剪切,不是完全删除,想关注返回结果 [1, 2] 拿变量接收,不想关注就不接收


在控制台上操作

image.png

截取后返回值 [1, 2]

截取后原数组变成 [1, 2, 3, 3]


再来,从第零为开始切,切三位,剩下的是什么?

var arr = [1, 1, 2, 2, 3, 3];

arr.splice(0, 3); // 返回[1, 1, 2]

console.log(arr); // 剩下[2, 3, 3]


再来,

1. 从第一位开始切,切一个,

2. 然后,后面加参数了,后面的参数是无穷个的个数,后面的参数包含什么意思呢?

    就是传多少个参数,都会把后面的参数全部放到切口处。传多少个都行,后面相当于在切口处的  push() 

var arr = [1, 1, 2, 2, 3, 3];

arr.splice(1, 1, 0, 0, 0); // [1]

console.log(arr); // [1, 0, 0, 0, 2, 2, 3, 3]

 [ 1, 1, 2, 2, 3, 3 ] 

 [ 1, 1, 0, 0, 0, 2, 2, 3, 3 ] 


那么问题来了,把 4 填到相应的位置上(3和5之间)怎么写?

var arr = [1, 2, 3, 5];

arr.splice(3, 0, 4); // []

console.log(arr); // [1, 2, 3, 4, 5]

[     1,          2,        3 ,            ,          5     ]

 第零位   第一位  第二位  第三位    第四位

1. 如果光标定位在第位不切,光标不往后移,

2. 在第三位定位,光标切0位就是不切,

3. 不切在这块填 4


再说明一下

1. 光标定位在第三位

2. 然后(这块很关键)然后光标就不切了,切0个,把刀疤留在这,不拿走东西,然后这块填东西

3. 不切的这块填 4


splice 方法用截取的次数概率比较小,用往里面填东西的概率比较大


有了splice方法之后,我们自己写的 MyUnshift 就好办了,在第 0 位开始截,截 0 个往里插东西就完事了,

splice 方法是非常强大的,会把截取完的的片段给反回来,还改变原数组。


splice 能从负数位开始截取吗?

从 -1 开始截取,截取一个(一般的数组方法都带负位)

var arr = [1, 2, 3, 4];

arr.splice(-1 ,1); // [4] 截取出来了

console.log(arr); // [1, 2, 3]

负一位 -1 的意思是倒数第一位,数组一般的方法里面都可以带负位的


数组在内部怎么实现负数的?

比如 spice 方法它第一个参数(pos)肯定是位置,pos 是怎么实现的,它是怎么把负数给归正的,也就是负一为什么是倒数第一位,为什么正一就是第二位?

var arr = [1, 2, 3, 4];

splice = function (pos){

  pos += pos > 0 ? 0 : this.length;

}


负一为什么是倒数第一位,为什么正一就是第二位?

如果传的是 -1,数组的 length 是 4,

公式是  -1 + 4 = 3  结果 3 是数组最后一位 4


如果传的是 -2,数组的 length 是 4,

公式  -2 + 4 = 2   结果 2 是数组正数二位 3


Ps:

编程尽量学完之后学的是编程,而不是学的是技术规律,技术规律没意思。

真正搞经济的人,真正在金融领域,高手之前都是编程的,我们这种程序化思维,特别有利于金融思维的启发。金融和编程是脱不了关系的,而且是相辅相成的。

所以把这个思维学会之后,想的是负数就是倒数第几位,可放到数字上实现的话就是另一种思维了,一定要学到这个过程,这是另一种思维法。


系统内部在实现 length 的时候,如果是负数的话,做这样一个兼容,如果是正数,正数就不用计算加了。

如果算负数,没法算负数,但是又想把负数的意义包含进来,怎么办法?加 lenght 就完事了。


如果越界,加一个判断(jQuery)

pos += pos > 0 ? 0 : this.length;

pos >= 0 || pos < length

算完的 pos,要大于等于 0 或者 pos 小 length,才有意义。


如果超界了,

数组的长度是5,放了一个 100 大于 length 不符合,

如果数组长度是5,放了一个 -100 它小于等于 0 了也不符合要求


7. sort()

给数组排序的,在原数组的基础上更改


1、sort 基本用法


arr 是一个无序的数组,无序数组想变成有序的怎么办?arr.sort()  会自小到大的顺序

var arr = [1,3,4,0,-1,9]; 

console.log(arr.sort()); //  [-1, 0, 1, 3, 4, 9]

console.log(arr); // [-1, 0, 1, 3, 4, 9]


上面是从小到大升序,想要从大到下降序 arr.sort().reverse() 这就降序了

var arr = [1,3,4,0,-1,9];

console.log(arr.sort().reverse());// [9, 4, 3, 1, 0, -1]


2、sort 的接口


换一个数组,用 sort() 方法升序排完是什么?结果这不是我们理想中的排序

var arr = [1,3,5,4,10];

console.log(arr.sort()); // [1, 10, 3, 4, 5]


sort() 把这些  [ 1, 3, 5, 4, 10 ] 全当成了字符按 ASCII 码排的,

sort() 可以按 ASCII 码排序字符,但是这个排序不是我们想要的,和我们要的相差甚远,我们想要的是数字排序


所以 sort() 方法留了一个编程接口,里面填一个匿名的 function 函数,这个 function 通过自己的方法填充完之后,就可以让 sort() 方法按照我们想要的任何一种方式来排序

var arr = [1,3,5,4,10];

arr.sort(function(a, b){
  // 匿名函数
});

function 里面必须要写两个形参,而且这个 functin 不用写名字,这就是一个函数引用


这个函数引用,类似于把这个 function 写到外面,把函数名 test 填进去,也是填个引用进去

var arr = [1,3,5,4,10];

arr.sort(test); // 2.函数引用test填进去

function test(){ // 1.函数写在外边
}

所以,function 莫不如直接在里面写了


这个 function 用不着我们自己去调用,把他当做参数传进去,系统会在适当的时候去调用,

只不过我们把 function 里面的规则写好就 OK 了


3、排序规则


function 里面的规则是什么呢?

1. 必须写两个形参

2. 看函数的返回值

   1). 当返回值为负数时,那么前面的数放在前面

   2). 当返回值为正数,那么后面的数在前面

   3). 返回值为 0,不动 

var arr = [1, 3, 5, 4, 10];

arr.sort(function (a, b){
  return ;
});


sort 会把里面的函数会调动无数次(具体多少次是可求的,有兴趣可以自己去求),每次执行的时候,会传里面两个参数

1. 首先第一次调用函数时时候,会把数组的第一位和第二位传进来

    第一位是 1

    第二位是 3

    第一次调用函数时会把 1, 3 传进来,传进来通过一系列规则比较

2. 当返回值为正数的时候,后面的数在前,

    比如返回为 return 1

    就会让 1, 3 调换位置为 3, 1 

    [ 3, 1, 5, 4, 10 ]

3. 当返回值为负数的时候,前面的数就在前,1,  3 不变

4. 具体什么时候返回值为正,什么时候返回值为负,就是我们控制的了


var arr = [ 1,  3,  5,  4,  10 ]  传参的顺序

第一轮

第一次传  1 3

第二次传  1 5

第三次传  1 4

第四次传  1 10


第二轮

然后传     3  5

然后传     3  4 

然后传     3  10    


第三轮                                    var arr = [ 1, 3, 5, 4, 10 ]

然后传     5  4      4 和 5 位置互换变成   [ 1, 3, 4, 5, 10 ]  

然后传     4  10    4 和 10 比较位置不变 [ 1, 3, 4, 5, 10 ]  


第四轮

然后传     5  10    [ 1, 3, 4, 5, 10 ]


上面的过程是升序符合冒泡排序的算法


升序就是从小到大 1 2 3 4 ...

接下来定义升序的规则,当 a 大于 b 的时候返回正数 1,否则返回负数 -1

var arr = [1, 3, 5, 4, 10];

arr.sort(function (a, b){
  if(a > b){
    return 1;
  }else{
    return -1;
  }
});

console.log(arr); //  [1, 3, 4, 5, 10]

第一遍传 1 3

1  3    [ 1, 3, 5, 4, 10 ] 

1  5    [ 1, 3, 5, 4, 10 ]

1  4    [ 1, 3, 5, 4, 10 ]

1  10  [ 1, 3, 5, 4, 10 ]


第二轮传 3 和 5 比 

3  5    [ 1,    3, 5, 4, 10 ]

3  4    [ 1,    3, 5, 4, 10 ] 

3  10  [ 1,    3, 5, 4, 10 ]


第三轮传 5 和 4 比

5  4    [ 1, 3,    4, 5, 10 ]  5 大于 4 换位置,后面数在前,两个数换一下位置

4  10  [ 1, 3,    4, 5, 10 ]  然后这个位置的和那个位置的比,不要认数,要认位置,4 跟 10 比小于,小于谁也不动


第四轮传 5 和 10 比

5  10  [ 1, 3, 4,    5, 10 ]


这是升序,我们通过系统留的接口,自定义规则弄出来的升序


再排序一个数组

var arr = [2, 10, 20, 13, 4, 18, 9];

arr.sort(function (a, b){
  if(a > b){
    return 1;
  }else{
    return -1;
  }
});

console.log(arr); // [2, 4, 9, 10, 13, 18, 20]


2   10    [ 2, 10, 20, 13, 4, 18, 9 ]

2   20    [ 2, 10, 20, 13, 4, 18, 9 ]

2   13    [ 2, 10, 20, 13, 4, 18, 9 ]

2   4      [ 2, 10, 20, 13, 4, 18, 9 ]

2   18    [ 2, 10, 20, 13, 4, 18, 9 ]

2   9      [ 2, 10, 20, 13, 4, 18, 9 ]


10  20   [ 2,   10, 20, 13, 4,   18, 9 ]

10  13   [ 2,   10, 20, 13, 4,   18, 9 ]

10  4     [ 2,   10, 20, 13, 4,   18, 9 ]   4 换到 10 位置

4    18   [ 2,    4,  20, 13, 10, 18, 9 ]

4    9     [ 2,    4,  20, 13, 10, 18, 9 ]


每一轮进行完后,会最小得数放前面


20  13     [ 2, 4,    20, 13, 10, 18, 9  ]   13 换到前面的位置

13  10     [ 2, 4,    13, 20, 10, 18, 9  ]   10 换到前面的位置 

10  18     [ 2, 4,    10, 20, 13, 18, 9  ]

10   9      [ 2, 4,    9,   20, 13, 18,10 ]    9 换到前面的位置  


前三位按循序了,第四位开始


20   13    [ 2, 4, 9,    20, 13, 18, 10 ]    13 换到前面的位置

13   18    [ 2, 4, 9,    13, 20, 18, 10 ]

13   10    [ 2, 4, 9,    10, 20, 18, 13 ]    10 换到前面的位置 


20   18    [ 2, 4, 9, 10,    20, 18, 13 ]    18 换到前面的位置

18   13    [ 2, 4, 9, 10,    18, 20, 13 ]    13 换到前面的位置

13   18    [ 2, 4, 9, 10,    13, 20, 18 ]


20   18    [ 2, 4, 9, 10, 13,    20, 18 ]     18换到前面的位置

18   20    [ 2, 4, 9, 10, 13,    18, 20 ]

这是数组 sort() 方法给我们的一个比较的顺序,比较的原则结合这个比较的顺序,就叫算法里面的冒泡排序,但今天讲的不是冒泡排序是数组的算法。


上面的完后是一个升序,变一下比较规则,当 a 小于 b 时返回降序

var arr = [2, 10, 20, 13, 4, 8, 9];

arr.sort(function(a, b){
  // a小于b变降序
  if(a < b){
    return 1;
  }else{
    return -1;
  }
});

console.log(arr); // [20, 13, 10, 9, 8, 4, 2]


var arr = [  2, 10, 20, 13, 4, 8, 9 ]


2   10     [ 2,  10,  20, 13, 4, 8, 9 ]    2 小于10  换位置 

10  20    [ 20,  2, 10, 13, 4, 8, 9 ]   10 小于20  换位置 

20  13    [ 20,  2, 10, 13, 4, 8, 9 ]

20  4      [ 20,  2, 10, 13, 4, 8, 9 ]

20  8      [ 20,  2, 10, 13, 4, 8, 9 ]

20  9      [ 20,  2, 10, 13, 4, 8, 9 ]


2  10      [ 20, 10,   2, 13, 4, 8, 9 ]    2 小于 10,换位置

10  13    [ 20, 13,   2, 10, 4, 8, 9 ]  10 小于 13,换位置  

13  4      [ 20, 13,   2, 10, 4, 8, 9 ]

13  8      [ 20, 13,   2, 10, 4, 8, 9 ]

13  9      [ 20, 13,   2, 10, 4, 8, 9 ]


2   10     [ 20, 13,    2, 10, 4, 8, 9 ]    2 小于 10,换位置

10  4      [ 20, 13,   10, 2, 4, 8, 9 ]

10  8      [ 20, 13,   10, 2, 4, 8, 9 ]

10  9      [ 20, 13,   10, 2, 4, 8, 9 ]


2   4      [ 20, 13, 10,    4, 2, 8, 9 ]    2 小于 4,换位置(这步就是已经换了的) 

4   8      [ 20, 13, 10,    8, 2, 4, 9 ]    4 小于 8,换位置 (这步就是已经换了的) 

8   9      [ 20, 13, 10,    9, 2, 4, 8 ]    8 小于 9,换位置 (这步就是已经换了的) 


2   4      [ 20, 13, 10, 9,    4, 2, 8 ]    2 小于 4 换位置 (这步就是已经换了的) 

4   8      [ 20, 13, 10, 9,    8, 2, 4 ]    4 小于 8 换位置 (这步就是已经换了的) 


2   4      [ 20, 13, 10, 9, 8,    2, 4 ]   2 小于 4  换位置

4   2      [ 20, 13, 10, 9, 8,    4, 2 ]

这一系列换完之后变降序了,通过 a 小于 b 的改变,可以控制升序降序


想让数组升序,换回a大于b

var arr = [2, 10, 20, 13, 4, 8, 9];

arr.sort(function(a, b){

  if(a > b){ // a大于b变升序
    return 1;
  }else{
    return -1;
  }
});

console.log(arr); // [2, 4, 8, 9, 10, 13, 20]


怎么没计算 0 呢?

0 反正也没变化,算它干嘛呢!


4、简化升序


接下来简化一下,有没有什么通式?

第一个数比第二个数大,才调换位置一定是升序

a 大 b 小,要把 b 放前面,肯定是升序,能不能总结一个通式?


换一种写法

当  a - b > 0   大于 0 的时候,要返回一个大于 0 的数,就是返回 a - b 的结果就完事了

当  a - b < 0   小于 0 的时候,要返回一个小于 0 的数,直接返回 a - b 的结果就完事了


也就是升序排列

当 a - b 大于 0 的时候,返回 a - b

当 a - b 小于 0 的时候,返回 a - b

var arr = [2,10,20,13,4,18,9];

arr.sort(function(a, b){

  if(a - b > 0){
    return a - b;
  }else{ a - b < 0
    return a - b;
  }

});

console.log(arr); // [2, 4, 8, 9, 10, 13, 20]


就是无论什么时候返回 a - b 都是升序,

当 a 小于 b 到时候,返回的是一个负数,

当 a 大于 b 的时候,返回到是一个正数还是 a  - b

var arr = [2,10,20,13,4,18,9];

arr.sort(function(a, b){
  return a - b; // 升序
});

console.log(arr); // [2, 4, 9, 10, 13, 18, 20]


5、简化降序


下面是降序的简化

a 小于 b 的时候返回  1,

a 大于 b 的时候返回 -1

var arr = [2,10,20,13,4,18,9];

arr.sort(function(a, b){

  if(a < b){
    return 1;
  }else{
    return -1;
  }

});

console.log(arr); // [20, 18, 13, 10, 9, 4, 2]


a 小于 b 就返回 b - a 就行了

a 大于 b 要返回负数还是要返回 b - a

var arr = [2,10,20,13,4,18,9];

arr.sort(function(a, b){
  if(a < b){
    return b - a;
  }else{
    return b - a;
  }
});

console.log(arr); // [20, 18, 13, 10, 9, 4, 2]


所以 return b - a 是降序

var arr = [2,10,20,13,4,18,9];

arr.sort(function(a, b){
  return b - a; // 降序
});

console.log(arr); // [20, 18, 13, 10, 9, 4, 2]


6、练习(面试题)


第一题:

给一个有序数组乱序


原题,随机打乱原数组的顺序,然后在一次性返回。


乱序的结果,就是每次的结果都是不一样的,这次执行和下次执行不一样。

首先先铺垫一下 Math.random() 产生 0 到 1 之间的开区间数 [0, 1),每次都不一样,特别小的小数

console.log(Math.random()); // 0.03409055182865539


Ps:

开区间就是不包括两头的数,不可能到 0 或 1,

闭区间就是包括 0 和 1


返回 0 到 1 之间的随机数,想让它可正数、可负数怎么办?

Math.random() - 0.5  或  0.5 - Math.random() 


既然返回的是 0 到 1 之间的开区间数,让 0.5 减去这个开区间数,因为开区间数有可能是 0 到 0.5 之间,也有可能是 0.5 到 1 之间,

这样概率一半一半,有可能正、有可能负,这样每次返回的是随机的值

console.log(0.5 - Math.random());


再用 sort() 方法排序,就是随机乱排了

var arr = [1,2,3,4,5,6,7];

arr.sort(function(){
  return Math.random() - 0.5;
});

console.log(arr); // 每次结果都不一样


第二题:

把下面对象放到数组里面,按照的对象的年龄排序(升序)

var Fang = {
  name : "fang",
  age : 40,
  sex : "male",
  face : "amazing"
}

var Lili = {
  name : "lili",
  age : 37,
  sex : "female",
  face : "amazing"
}

var Glee = {
  name : "Lu",
  age : 36,
  sex : "female"  
}

var arr = [Fang, Lili, Glee]; // 把对象放到数组里

arr.sort(function (a ,b){

  if(a.age > b.age){
    return 1;
  }else{
    return -1;
  }
  // 还可以这样简化 return a.age - b.age;

});

console.log(arr);

关键知道原理是什么,把参数 a, b 用灵活了,知道原理想怎么排序怎么排


第三题:

按照字符串长度排序

var arr = ['abc', 'bcd', 'ccc', 'dddd', 'asdfkhiuqwe', 'asdoifqwoeiur', 'asdf'];

arr.sort(function (a ,b) {
  return a.length - b.length;
});

console.log(arr); //["abc", "bcd", "ccc", "dddd", "asdf", "asdfkhiuqwe", "asdoifqwoeiur"]


第四题:

按照字节长度排

var arr = ['abc莉莉', 'bcd莉', 'c莉', 'dddd莉', 'asdfkhiuqwe莉莉', 'asdoifqwoeiur', 'asdf'];

// 先封装一个方法,计算字节的长度
function retBytes(str) {
  var num = str.length;
  for (var i = 0; i < str.length; i++) {
    if (str.charCodeAt(i) > 255) {
      num++;
    }
  }
  return num;
}

arr.sort(function(a, b) {
  return retBytes(a) - retBytes(b);
});

console.log(arr); // ["c莉", "asdf", "bcd莉", "dddd莉", "abc莉莉", "asdoifqwoeiur", "asdfkhiuqwe莉莉"]

先写一个 retBytes 方法返回字节长度,小功能实现完之后漫漫拓展,能成为一个很复杂的东西


二、不可以改变原数组的方法

这些方法特别简单 concat, join—>split, toString, slice


8. concat()

concat 方法是链接两个数组,会把后面的数组(arr1)拼到前面的数组(arr)上,并且规则发生了改变。

var arr = [1,2,3,4,5,6];
var arr1 = [7,8,9];

// 拼接
console.log(arr.concat(arr1)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 原数组不改变
console.log(arr); // [1, 2, 3, 4, 5, 6]
console.log(arr1); // [7, 8, 9]


上面学过的都是能改变原数组的,

这几个 concat, join—>split, toString, slice 是改变不了的,

改变不了的意思是 concat() 拼完是一个全新的数组,不影响原来的两个原数组。concat 是计算机给英语造出来的词链接的意思。


9. toString()

数组的 toString 方法,就是把数组变成字符串展示出来,是数组自己重写的

var arr = [1,2,3,4,5,6];

var str = arr.toString();

console.log(str); // ”1,2,3,4,5,6”


10. slice()

slice 方法是截取和 splice 有点相像又不一样,

slice 里面可以填 0 个参数,可以填一个参数,也可以填两个参数


先看填两个参数的  slice( 从该位开始截取, 截取到该位 )  不是“截取了”是“截取到

var arr = [1,2,3,4,5,6];

var newArr = arr.slice(1, 2); // 从第一位的2开始截取,截取到第二位的3,不包括第二位的3

console.log(newArr); // [2]

console.log(arr); // [1,2,3,4,5,6]

 [  1,          2,          3,        4,          5,        6]

 第零位  第一位  第二位  第三位...

1 是第零位,

2 是第一位,

只截取到第二位的 3

从第一位开始截取,截取到第二位


看原数组还那样 [ 1, 2, 3, 4, 5, 6 ],

不改变原数组,关注的只能是返回值,所以 slice 截取完,千万要拿一个变量接收,否则 slice 没有意义。


从第一位开始截取,截取到第三位呢?

var arr = [1, 2, 3, 4, 5, 6];

var newArr = arr.slice(1 ,3);

console.log(newArr); // [2, 3]

console.log(arr); // [1, 2, 3, 4, 5, 6]


一个参数的情况是,从第几位开始截取,一直截取到最后

var arr = [1, 2, 3, 4, 5, 6];

var newArr = arr.slice(1);

console.log(newArr); // [2, 3, 4, 5, 6]

从第一位开始截取,一直截取到最后返回 [ 2, 3, 4, 5, 6 ]


当然还可以填负数,从负四开始( -4 + 6 = 2 )就是倒数第四位,相当于从正数第二位开始

var arr = [1, 2, 3, 4, 5, 6];

var newArr = arr.slice(-4);

console.log(newArr); // [3, 4, 5, 6]


要是不懂负数,直接加 length 就完事了,

当然系统提供负数是为了让我们更好的理解的,-4 就是倒数第四个(倒数直接


不写参数就是整个截取,整个截有用吗?

想把一个“类数组”转化成数组就用 sliec() 空截

var newArr = arr.slice();

console.log(newArr);// [1, 2, 3, 4, 5, 6]


最后一个方法 join —> split


11. join()

这个方法了不得,join() 里面可以传参数,参数传什么都行,但是必须是字符串形式的,传空串也得是字符串


如果传 "-" 它会把数组里的每一位都链接起来并返回一个字符串

var arr = [1,2,3,4,5,6];

var arrStr = arr.join("-");

console.log(arrStr);//1-2-3-4-5-6


它会把数组的每一位都链接起来,按照传的参数去链

var arrStr1 = arr.join("!");
console.log(arrStr1);//1!2!3!4!5!6


var arrStr2 = arr.join("~");
console.log(arrStr2);//1~2~3~4~5~6


12. split()

和 join() 可逆的是 split() 方法,split() 是字符串的方法不是数组的,但它却和数组方法可逆的

split() 方法是按照什么拆分成数组,字符串有方法能拆分能数组,数组有方法能组合成字符串


按照 "-" 来拆分为数组

var str = "1-2-3-4-5-6";

var arr1 = str.split("-");

console.log(arr1);// ["1", "2", "3", "4", "5", "6"]


按那个拆分就把那个给咔嚓了就没了,按 4 拆就截取符了 4 就没了,按照 "-" 拆 "-" 就没了

var arr2 = str.split("4");

console.log(arr2); // ["1-2-3-", "-5-6"]


split() 可以返回数组,

join()  数组可以返回字符串


应用一下,

这个 join 到底是在哪应用的,这么多的字符串形式拼到一起。之前有这么一个面试题,给50个公司的名称,把50个名称拼到一起。

var str = "alibaba";
var str1 = "baidu";
var str2 = "tencent";
var str3 = "toutiao";
var str4 = "wangyi";
var str5 = "xiaowang";
var str6 = "nv";


第一种方法,字符串拼接

var strFinal = str + str1 + str2 + str3 + str4 + str5  + str6;

console.log(strFinal);


第二种方法,写到一个数组里面

var arr = [str, str1, str2, str3, str4, str5, str6],
    len = arr.length,
    strFinal = '';

for(var i = 0; len > i; i ++){
  strFinal += arr[i];
}

console.log(strFinal);


原始值字符串在栈里面存储,栈内存有个规则先进后出,

访问栈内存的时候,要拿出来拼到一起,再拿出来拼到一起,来回折腾这个栈,效率肯定低,

所以字符串的链接是一种栈内存的链接,链完之后效率是低的,尽量不用栈内存。


数组是散列存储结构是堆内存,如果把这些东西全放到数组里面去,然后利用数组是通过散列的算法去找,最后用 join() 方法这样效率是高的

var arr = [str, str1, str2, str3, str4, str5, str6];

var strFinal = arr.join("");//这里不需要用什么来链传空串就行,不传arr.join()它默认用逗号链

console.log(strFinal);


Ps: 

头条的深度算法,人工智能的推送是最强的。

但凡上头条之后新闻就看不断了,它能把你所喜欢的东西一起全给你。

让你不断的看不断的占用你的精力,而大家普遍喜欢的资源还特别多。

比如女生喜欢购物喜欢时装这种东西你就看去吧,你要认真的话这辈子就这么过去吧!绝对给你推送让你看不完!



Leave a comment 0 Comments.

Leave a Reply

换一张