认识JS的Array类型

ECMAScript数组的每一项可以保存任何类型的数据,并且数组的大小是可以动态调整的。
创建数组的基本方式有两种,分别是

  • 使用Array构造函数

我们可以给构造函数传递数组长度,或者数组的内容。

1
2
3
var people = new Array()
var nums = new Array(3)
var colors = new Array('red', 'blue', 'yellow')

当你给构造函数传值时,可以不用new操作符

1
var nums = Array(3)
  • 使用数组字面量表示法。

数组字面量由一对包含数组项的方括号表示,多个数组项以逗号隔开。

1
2
3
4
var colors = ['red', 'blue', 'yellow']
var nums = [] // 创建一个空数组
var values = [1, 2, ] // 反面例子哈,不要这样写
var options = [,,,,,,,] // 反面例子哈,不要这样写

在读取和设置数组的值时,要使用方括号并提供相应的索引值(从0开始)

1
2
3
var colors = ['red', 'blue', 'yellow']
console.log(colors[0]) // red
colors[1] = 'green'

数组的length属性很有特点,它不是只读的,你可以从数组移项,也可以往数组添加项,如下

1
2
3
var colors = ['red', 'blue', 'yellow']
colors.length = 2
console.log(colors[2]) // undefined, yellow被移除了

数组的长度等于最后一项的索引加一

1
2
3
var colors = ['red', 'blue', 'yellow']
colors[99] = 'pink'
console.log(colors.length) // 100

检测数组

可以使用instanceof判断某个对象是不是数组

1
2
3
if (value instanceof Array) {
// ......
}

但是它只假定只有一个全局环境,如果遇到两个全局环境就不适用了,什么时候会有多个全局环境呢,就是网页中有多个框架的时候。

因此有一个更好的方法检测数组,就是Array.isArray()

1
2
3
if (Array.isArray(value)) {
// .....
}

转换方法

所有对象都有,每次所有对象都有toLocaleString(), toString(), valueOf()方法。数组调用valueOf返回的还是数组本身;而调用数组的toString()会去调用每一项的toString()方法然后拼接成一个以逗号分隔的字符串,同理,toLocaleString()也是如此。

1
2
3
4
5
6
7
var colors = ['red''blue''green']
console.log(colors.toString()) // red,blue,green
console.log(colors.valueOf()) // [ 'red', 'blue', 'green' ]
console.log(colors) // [ 'red', 'blue', 'green' ]
alert(colors.toString()) // red,blue,green
alert(colors.valueOf()) // red,blue,green
alert(colors) // red,blue,green

以上三种方法默认情况下都是以逗号分隔项
如果你使用join就可以用不同的分隔符来构建这个字符串,如下

1
2
3
var colors = ['red''blue''green']
console.log(colors.join(',')) // red,blue,green
console.log(colors.join('||')) // red||blue||green

栈方法

栈是一种LIFO(last in first out,后进先出)的数据结构,也就是最新添加的项最早被移除,它可以限制插入和删除项。
数组的push和pop方法就表现得跟栈类似。

  • push():可以接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度,注意是返回数组长度。
  • pop(): 从数组末尾移除最后一项,减少数组的length,然后返回移除的项,注意返回的是移除的项。
1
2
3
4
5
6
var colors = ['red''blue']
colors.push('yellow')
colors[3] = 'black'
console.log(colors.length) // 4
var item = colors.pop()
console.log(item) // black

队列方法

队列是一种FIFO的数据结构(先进先出),前面栈是后进先出。队列在列表的末端添加项,从列表的前端删除项。
这里介绍一种删除数组项的方法shift(),它能够删除数组中的第一项并返回该项,同时将数组长度减一,注意返回的是删除项!
要像使用队列一样使用数组,实现方法就是shift()+push()

1
2
3
4
5
6
7
8
9
10
11

var colors = new Array()
var count = colors.push('red','black')
console.log(count) // 2

count = colors.push('pink')
console.log(count) // 3

var item = colors.shift()
console.log(item) // red
console.log(colors.length) // 2

这里再介绍一个方法unshift(), 顾名思义,unshift()与shift()的用途相反,它是在数组前端添加任意个项并返回数组的长度。
如果想从相反方向模拟队列,就是unshift()+pop()

1
2
3
4
5
6
7
8
9
10
var colors = new Array()
var count = colors.unshift('red','black')
console.log(count) // 2

count = colors.unshift('pink')
console.log(count) // 3

var item = colors.pop()
console.log(item) // black
console.log(colors.length) // 2

重排序方法

reverse()和sort()

  • reverse():就是反转数组项的顺序

    1
    2
    3
    var arr = [1,2,3,4,5]
    arr.reverse()
    console.log(arr) // [ 5, 4, 3, 2, 1 ]
  • sort():按照升序(从小到大)给数组项排序
    sort()比较的是字符串(数组项转为字符串),也就是说如果直接用它,数组项为数值的排序结果并不理想

    1
    2
    3
    var arr = [0,1,5,10,15]
    arr.sort()
    console.log(arr) // [ 0, 1, 10, 15, 5 ]

因此,sort()方法可以接收一个比较函数作为参数,这个比较函数接收两个参数。(面试题经常出现这种比大小的题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function compare(v1,v2){
    // if(v1 > v2){
    //     return 1
    // } else if(v1 < v2){
    //     return -1
    // } else{
    //     return 0
    // }
// 升序
    return v1 - v2
// 降序
// return v2 - v1
}
var arr = [0,1,50,10,15// [ 0, 1, 10, 15, 50 ]
console.log(arr.sort(compare))

操作方法

  • concat():基于当前数组中的所有项创建一个新数组,不改变原数组

具体来说就是,先创建当前数组的一个副本,然后将接收到的参数添加在数组末尾。

  1. 不给concat()方法传递参数,它只是返回创建的副本。
  2. 给concat()方法传递一个或者多个数组,它会将数组中的每一项添加到创建的数组副本中。
  3. 给concat()方法传递非数组的值,它会把这些值直接添加到数组末尾。
    1
    2
    3
    4
    var colors = ['red''green''blue']
    var colors2 = colors.concat('pink', ['black''yellow'])
    console.log(colors) // [ 'red', 'green', 'blue' ]
    console.log(colors2) // [ 'red', 'green', 'blue', 'pink', 'black', 'yellow' ]
  • slice():基于当前数组的一个或多个项创建一个新数组,不改变原数组

slice()方法可以接收一个或者两个参数,即要返回的项的起始和结束位置(不包括结束位置的项)

  1. 只接收一个参数,则返回从该参数指定位置的项到当前数组末尾的所有项。
  2. 接收两个参数,则返回起始和结束位置之间的项(包括起始位置的项,但不包括结束位置的项)
    1
    2
    3
    4
    5
    6
    var colors = [ 'red''green''blue''pink''black''yellow' ]
    var colors2 = colors.slice(1)
    console.log(colors2) // [ 'green', 'blue', 'pink', 'black', 'yellow' ]
    var colors3 = colors.slice(2,4)
    console.log(colors3) // [ 'blue', 'pink' ]
    console.log(colors) // [ 'red', 'green', 'blue', 'pink', 'black', 'yellow' ]

如果slice接收的参数是负数,则用数组长度加上该数来确定相应的位置。如在一个长度为5的数组调用slice(-2, -1), 等于slice(3, 4)。如果结束位置小于起始位置,则返回空数组。

  • splice():主要用途是向数组中部插入项,会改变原数组。
  1. 删除:可以指定2个参数(要删除的第一项的位置和要删除的项数),然后删除任意数量的项。
    1
    2
    3
    4
    var colors = ['red''green''blue''yellow']
    var colors1 = colors.splice(1,2)
    console.log(colors) // [ 'red', 'yellow' ]
    console.log(colors1) // [ 'green', 'blue' ]

从上面例子可以看出,splice()方法返回的是删除的项所组成的数组,如果没有删除的项,则返回空数组,下面例子可见。

  1. 插入&替换:输入三个参数(起始位置,要删除的项数,要插入的项),如果插入多个项,可以有第四、第五个参数;如果要删除的项为0,那就是插入作用;如果不为0那就是替换。
1
2
3
4
5
6
7
var colors = ['red''green''blue''yellow']
var colors1 = colors.splice(10'pink')
console.log(colors1) // []
console.log(colors) // [ 'red', 'pink', 'green', 'blue', 'yellow' ]
var colors3 = colors.splice(02'white''orange')
console.log(colors3) // [ 'red', 'pink' ]
console.log(colors) // [ 'white', 'orange', 'green', 'blue', 'yellow' ]

位置方法

indexOf()和lastIndexOf(),都接收一个或两个参数(分别是要查找的项和查找的起始位置的索引),indexOf从数组开头的位置(默认0)开始向后查找,lastIndexOf从数组结尾的位置(默认length-1)开始向前查找。

这两个方法都返回要查找的项在数组中的位置,在没有找到的情况下返回-1;它在查找的时候是使用全等操作符(===),也就是查找的项必须严格相等。

1
2
3
4
5
6
7
8
9
10
11
var nums = [123454321]
console.log(nums.indexOf(4)) // 3
console.log(nums.lastIndexOf(4)) // 5
console.log(nums.indexOf(44)) // 5
console.log(nums.lastIndexOf(44)) // 3
var person = {name'Amy'}
var people = [{name'Amy'}]
var morePeople = [person]
console.log(morePeople.indexOf(people)) // -1
console.log(morePeople.indexOf(person)) // 0
console.log(person == people[0]) // false

迭代方法

数组的5种迭代方法,每个方法接收两个参数,分别是要在每一项上运行的函数以及运行该函数的作用域对象——影响this的值。要在每一项上运行的函数接收三个参数,分别是数组项的值,该项在数组中的位置,以及该数组本身。
以下是这5种方法:

  • every():若数组所有项都使得运行函数返回true(即每一项都满足运行函数的要求),则返回true。
  • some():若数组中只要有一项使得运行函数返回true(有一项满足运行函数的要求),则返回true。
  • filter():返回查询数组中符合某些条件的所有数组项。
  • map():返回包含的项跟数组一一对应的数组。
  • forEach():相对于for循环,对数组每一项进行操作,没有返回值。

every()

1
2
3
4
5
var nums = [123454321]
var everyResult = nums.every((item,index,arr)=>{
    return item > 2
})
console.log(everyResult) // false

一旦发现不符合要求的,立马返回false,不去校验剩余的每一项

some()

1
2
3
4
5
var nums = [123454321]
var someResult = nums.some((item,index,arr)=>{
    return item > 2
})
console.log(someResult) // true

一旦发现符合要求的,立马返回true,不去校验剩余的每一项

filter()

1
2
3
4
5
var nums = [123454321]
var filterResult = nums.filter((item,index,arr)=>{
    return item > 2
})
console.log(filterResult) // [ 3, 4, 5, 4, 3 ]

map()

1
2
3
4
5
var nums = [123454321]
var mapResult = nums.map((item,index,arr)=>{
    return item * 2
})
console.log(mapResult) // [ 2, 4, 6, 8, 10, 8, 6, 4, 2 ]

forEach()

1
2
3
4
var nums = [123454321]
nums.forEach((item,index,arr)=>{
    // 执行的操作
})

三个参数不一定都要传,但至少要操作的数组项要传。

归并方法

reduce()和reduceRight()这两个方法会迭代数组所有项,然后构建最终返回的值。

reduce()方法从数组第一项开始遍历到最后,reduceRight()从数组最后一项开始遍历到最前面。

两个方法都接收两个参数:在每一项上执行的函数以及(可选的)作为归并基础的初始值。
在每一项上执行的函数接收四个参数:前一个值(就是上一次操作结果的值)、当前值、当前值在数组中的索引值、以及数组本身(不一定要四个值都传递)

使用reduce求和:

1
2
3
4
5
var nums = [123454321]
var sum = nums.reduce((prev, curr)=>{
    return prev + curr
})
console.log(sum) // 25