JavaScript数组操作的一些方法

数组的操作方法有很多,根据特性总的来说可以划分为三类,也就是

  • Mutator 改变原数组对象值的方法
  • Accessor 不改变原数组对象带返回值的方法
  • Iteration 数组遍历的方法

修改原数组方法

添加删除 pop, push, shift, unshift

可以通过一个图来解释
image
这些操作都会修改数组的length值。对于类数组,可以使用apply调用

排序 reverse, sort

reverse方法将数组前后位置颠倒,所以一种逆序字符串的方法可以写成

1
2
let str = 'hello'
str.split('').reverse().join(''); //'olleh'

sort() 方法提供了可选的规则对数组进行排序,默认会把元素按照转换为的字符串的每个字符的Unicode位点进行排序。
比如,1,10,21,2默认排序的结果为1,10,2,21
sort() 方法可以接收一个回调函数callback(a, b)用作设置比较规则,它的返回值的几种对应情况:

  • 小于 0, a 会被排列到 b 之前;
  • 等于 0, a 和 b 的相对位置不变;
  • 大于 0, b 会被排列到 a 之前。

对于数字的比较也可以简单的使二者相减来实现升序排列:

1
2
3
function compareNumbers(a, b) {
return a - b;
}

而降序返回b-a即可。那么回到前面的数组,升序排列的函数使用ES6的话可以便捷的写成:

1
[1,10,21,2].sort((a,b)=>a-b); //[1,2,10,21]

splice

splice()可以删除、添加数组元素

array.splice(start[, deleteCount, item1, item2, …])

可接收3个参数

  • start​ 指定修改的开始位置。
    • 如果超出了数组的长度,则从数组末尾开始添加内容;
    • 如果是负值,则表示从数组末位开始的第几位(从1计数)。
  • deleteCount 表示要移除的数组元素的个数。
    • 如果 deleteCount 是 0,则不移除元素。
    • 如果 deleteCount 大于start 之后的元素的总数,则从 start及后面的元素都将被删除。
    • 如果deleteCount被省略,则其相当于(arr.length - start)。
  • item1, item2, … 要添加进数组的元素,从start 位置开始。

splice()操作可以返回被删除元素的数组,如果没有删除则返回空数组

1
2
3
4
let arr = [1,10,21,2]
arr.splice(2, 0, 32) // [1, 10, 32, 21, 2]
arr.splice(-2, 0, 3) // [1, 10, 32, 3, 21, 2]
arr.splice(3, 1, 43) // [1, 10, 32, 43, 21, 2]

所以替换操作也就相当于是先删掉部分元素后再插入相同数量的元素

填充 fill, copyWithin

fill方法使用给定值,填充一个数组。

arr.fill(value, start, end)

  • value 填充值
  • start 填充起始位置
  • end 填充结束位置
1
2
3
[1, 2, 3].fill(4, 1, 2) // [1, 4, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({length: 3}, 4) // {0: 4, 1: 4, 2: 4, length: 3}

arr.copyWithin(target, start, end)

数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
它接受三个参数。

  • target(必需):从该位置开始替换数据。
  • start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
  • end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
1
2
[1, 2, 3, 4, 5].copyWithin(-2); // [1, 2, 3, 1, 2]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4); // [4, 2, 3, 4, 5]

不修改原数组方法

返回数组 concat,slice

concat() 方法用于合并两个或多个数组。

let newArr = oldArr.concat(value1[,valueN…])

1
2
3
4
5
let arr1 = ['reading','running']
let arr2 = ['playing', 'coding']
let arr3 = ['shopping', 'swimming']
let arr = arr1.concat('singing',arr2, arr3)
// ["singing","reading", "running", "playing", "coding", "shopping", "swimming"]

slice()方法返回一个从目标数组浅拷贝的部分或全部

slice(start, end)

  • start 提取开始的索引值,如果为负数表示从倒数第几个索引开始
  • end 提取结束的索引值,如果为负数表示从倒数第几个结束;如果被省略或者大于数组长度,会提取到末尾

提取结果包含start,但不包含end

1
2
3
4
let arr = ["singing","reading", "running", "playing", "coding"]
arr.slice() //["singing","reading", "running", "playing", "coding"]
arr.slice(1,3) //["reading", "running"]
arr.slice(-3, -1) //["running", "playing"]

返回字符串 join,toString

join()可接收一个字符串作为连接符

对于数组对象,toString() 方法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。

1
2
3
let arr = ["reading", "running", "playing", "coding"]
arr.join('-') //"reading-running-playing-coding"
arr.toString() // "reading,running,playing,coding"

返回位置 indexOf, lastIndexOf

indexOf()方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。
lastIndexOf()方法从后向前找

arr.indexOf(searchElement[, fromIndex = 0])

arr.lastIndexOf(searchElement[, fromIndex = 0])

  • searchElement 要查找的元素
  • fromIndex 开始查找的位置。
    • 如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。
    • 如果参数中提供的索引值是一个负值,表示从array.length + fromIndex索引开始查找。
1
2
3
let arr = ["reading", "running", "playing", "coding"]
arr.indexOf('coding') // 3
arr.indexOf('playing', -1) // -1

返回布尔值 includes

includes() 方法用来判断当前数组是否包含某指定的值,如果是,则返回 true,否则返回 false

arr.includes(searchElement, fromIndex)

  • searchElement 需要查找的元素值。
  • fromIndex 可选 从该索引处开始查找 searchElement。如果为负值,则从array.length + fromIndex索引开始搜索。
1
2
3
let arr = ["reading", "running", "playing", "coding"]
arr.includes('playing') // true
arr.includes('singing') // false

遍历方法

forEach, filter, map

forEach() 方法对数组的每个元素执行一次提供的函数。
forEach()的返回值是undefinedfiltermap会返回新数组

array.forEach(callback[, thisArg])

  • item 数组当前项的值
  • index 数组当前项的索引
  • array 数组对象本身

jQuery/zepto的each方法接收的参数为

  • index 选择器的 index 位置
  • element 当前的元素(也可使用 “$(this)” 选择器)

filter表示筛选,满足条件的元素被返回,组成一个新数组
map函数对原数组每个元素调用条件函数,并把执行后的结果返回,组成一个新数组
callback参数

  • item 数组当前项的值
  • index 数组当前项的索引
  • array 数组对象本身

const newArr = arr.filter(callback[, thisArg])

const newArr = arr.map(callback[, thisArg])

1
2
let filtered = [1,10,2,21].filter((item)=> item > 9) // [10, 21]
let mapped = [1,10,2,21].map((item)=> item*2) // [2, 20, 4, 42]

返回布尔值 every, some

这两个方法的类似”与”和”或”,every表示数组中每个元素都符合条件则返回true,而some表示有一个元素符合就返回true

arr.every(callback[, thisArg])

arr.some(callback[, thisArg])

callback接收的参数

  • item 数组当前项的值
  • index 数组当前项的索引
  • array 数组对象本身
1
2
[1,10,2,21].every((item)=>item>10) // false
[1,10,2,21].some((item)=>item>10) // true

find, findIndex

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
callback接收的参数

  • item 数组当前项的值
  • index 数组当前项的索引
  • array 数组对象本身
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[1,10,2,21].find((item)=> item > 9) //10
[1,10,2,21].findIndex((item)=> item > 9) //1
let todos = [{
title:'reading', done: false
},{
title:'runing', done: true
},{
title:'shopping', done: false
}]
todos.find((item)=>{
return item.title == 'reading'
}) // {title: "reading", done: false}
todos.findIndex((item)=>{
return item.title == 'reading'
}) // 0

reduce,reduceRight

reduce() 方法对累加器和数组中的每个元素 (从左到右)应用一个函数,将其减少为单个值。
reduceRight()reduce() 的执行方向相反

  • callback接收参数
    • accumulator 上一次调用回调返回的值,或者是提供的初始值(initialValue)
    • currentValue 数组中正在处理的元素
    • currentIndex 数据中正在处理的元素索引,如果提供了 initialValue ,从0开始;否则从1开始
    • array 调用 reduce 的数组
  • initialValue 可选项,其值用于第一次调用 callback 的第一个参数。
    • 如果数组为空并且没有提供initialValue, 会抛出TypeError
    • 如果数组仅有一个元素(无论位置如何)并且没有提供initialValue,
    • 如果有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
1
2
3
let sum = [0, 1, 2, 3].reduce(function(acc, val) {
return acc + val;
}, 0); //6

MDN上提供了一种使用reduce扁平化数组的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// reduce 扁平化数组
let list1 = [[0, 1], [2, 3], [4, 5]];
let list2 = [0, [1, [2, [3, [4, [5, [6]]]]]]];
const flatten = (arr) => {
return arr.reduce(
(acc, val) => {
return acc.concat(Array.isArray(val) ? flatten(val) : val)
}, []
);
};
flatten(list1);
// [0, 1, 2, 3, 4, 5]
flatten(list2);
// [ 0, 1, 2, 3, 4, 5, 6 ]

entries, keys, values

返回一个遍历器对象,可以用for…of循环进行遍历,区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

其他

Array.of

在使用Array()构造数组时会因为参数个数差异而产生不同结果

1
2
3
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

Array.of的表现比较统一,只返回参数值组成的数组

1
2
3
4
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]

Array.from

Array.from把类数组和可遍历的对象转换为数组,(String,Set, Map,…)

Array.from(arrayLike[, mapFn[, thisArg]])

  • arrayLike 想要转换成真实数组的类数组对象或可遍历对象。
  • mapFn 可选参数,如果指定了该参数,则最后生成的数组会经过该函数的加工处理后再返回。
  • thisArg 可选参数,执行 mapFn 函数时 this 的值。
1
2
3
4
Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']

一种数组去重的方法也应用了Array.from

1
2
3
4
function uniq(array) {
return Array.from(new Set(array));
}
uniq([1, 2, 3, 3]) //[1, 2, 3]

因为Set结构的元素是唯一的,所以将数组转为Set结构再使用Array.from()就可以对数组去重

Array.isArray

判断是否为数组,返回true/false

总结

心好累……
不过总算是把数组常用方法复习了一遍

参考

ECMAScript 6 入门
MDN Array