前言
最近,针对JavaScript中的数组方法进行了复习,为了避免自己忘记并能够及时回顾,特此总结。
检测数组 instanceof & Array.isArray()
判断一个对象是不是数组,是返回true,不是返回false。
console.log([1,2,3] instanceof Array) //true
console.log(Array.isArray([1,2,3])) //true
转换方法 toString() & toLocalString() & valueOf() & join()
toString() & toLocalString()会将数组转换为字符串,并用','分隔数组的每一项。
console.log([1,2,3].toString()) //1,2,3
console.log([1,2,3].toLocaleString()) //1,2,3
valueOf()方法会返回数组本身。
console.log([1,2,3].valueOf()) //[1, 2, 3]
join()方法只接收一个参数,并将该参数作为分隔符,返回包含所有数组项的字符串。
console.log([1,2,3].join('|')) //1|2|3
添加删除方法 push() & pop() & shift() & unshift()
push()接收多个参数,将参数逐个添加到数组末尾,并返回修改后的数组长度。
console.log([1,2,3].push(4,5,6)) //6
pop()移除数组最后一项,并返回移除的项。
console.log([1,2,3].pop()) //3
unshift()接收多个参数,将参数逐个添加到数组前端,并返回修改后的数组长度。
console.log([1, 2, 3].unshift(-2, -1, 0)) //6
shift()移除数组第一项,并返回移除的项。
console.log([1, 2, 3].shift()) //1
重排序方法 reverse() & sort()
reverse()返回颠倒后的数组。
console.log([1, 2, 3].reverse()) //[3, 2, 1]
sort()升序或者降序排序数组,可以接收一个比较函数作为参数,以便指定升序或者降序。默认情况下sort()方法按升序排序数组,但是由于在默认情况下sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串,所以可能会导致排序错误发生。
console.log([5, 10, 15, 20].sort() //[10, 15, 20, 5]
出现上述问题,是由于JavaScript的字符串比较方式导致的,JavaScript中字符串间的比较是按照位次优先,比较各字符的ASCII大小,包括数字字符串之间的比较,所以'5'>'10'>'15'>'20'。
console.log([1, 5, 10, 15, 20].sort(function (value1, value2) {
return value1 - value2
})
) //[1, 5, 10, 15, 20]
升序排序,如果参数1>参数2,则会返回一个正数,那么参数1就会位于参数2之后,如果参数1<参数2,则会返回一个负数,那么参数1就会位于参数2之前,降序排序同理。
操作方法 concat() & slice() & splice()
concat()可以接收多个参数,参数可以是单个字符串,也可以是数组,concat()可以基于当前数组的所有项创建一个新数组,不会改变原数组。
console.log([1,2,3].concat([4,5,6])) //[1, 2, 3, 4, 5, 6]
slice()可以接收一个或两个参数,如果只有一个参数,slice()方法返回从指定位置开始到数组末尾所有的项,如果有两个参数,该方法返回起始位置和结束位置之间的项,但不包含结束位置的项,不会改变原数组。
console.log([1, 2, 3, 4, 5].slice(2)) //[3, 4, 5]
console.log(arr.slice(1, 3)) //[2, 3, 4]
splice()可以接收两个或多个参数,第一个参数为要删除的第一项的位置,第二个参数为要删除的项数,之后的参数为插入的项,该方法始终会返回一个包含从原始数组中删除的项的数组,如果没有删除任何项,则为空数组,该方法会改变原数组。
var arr = [1, 2, 3, 4, 5]
console.log(arr.splice(2, 2)) //[3, 4]
console.log(arr) //[1, 2, 5]
var arr = [1, 2, 3]
console.log([1, 2, 3].splice(arr.length, 0, [4, 5])) //[]
console.log(arr) //[1, 2, 3, [4, 5]]
这里有一个需要注意的问题,如果传入的参数是非字符串,那么splice()也会将该参数当作是一个单独的数组项插入原数组。
位置方法 indexOf() & lastIndexOf()
这两个方法都接收两个参数,要查找的项和查找起点位置的索引,如果查找到了该项,则返回该项在数组中的位置,否则返回-1,需要注意的是,在查找的过程中,会使用全等操作符(===),lastIndexOf()和indexOf()的唯一区别是该方法会从数组的末尾开始向前查找。
console.log([1, 2, 3, 1, 2, 3].indexOf(3)) //2
console.log([1, 2, 3, 1, 2, 3].indexOf(3, 3)) //5
console.log([1, 2, 3, 1, 2, 3].indexOf('1')) //-1
console.log([1, 2, 3, 1, 2, 3].lastIndexOf(3)) //5
console.log([1, 2, 3, 1, 2, 3].lastIndexOf(3, 3)) //2
console.log([1, 2, 3, 1, 2, 3].lastIndexOf('1')) //-1
迭代方法 some() & every() & filter() & forEach() & map()
some()对数组中的每一项运行给定函数,如果该函数任一项返回true,则返回true。
console.log([1, 2, 3, 4, 5].some(function (item, index, array) {
return item > 3
})
) //true
every()对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
console.log([1, 2, 3, 4, 5].every(function (item, index, array) {
return item > 3
})
) //false
filter()对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
console.log([1, 2, 3, 4, 5].filter(function (item, index, array) {
return item > 3
})
) //[4, 5]
forEach()对数组中的每一项运行给定函数,无返回值。
console.log([1, 2, 3].forEach(function (item, index, array) {
// 执行各种操作
console.log(item, index, array)
// 1 0 [1, 2, 3]
// 2 1 [1, 2, 3]
// 3 2 [1, 2, 3]
})
) //undefined
map()对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
console.log([1, 2, 3].map(function (item, index, array) {
return item * 2
})
) //[2, 4, 6]
归并方法 reduce() & reduceRight()
这两个方法都会迭代数组的所有项,然后构建一个最终返回的值,其实reduce()从数组的第一项开始,逐个遍历到最后,reduceRight()则相反。这两个方法都接收两个参数,在每一项上调用的函数和作为归并基础的初始值。在每一项上调用的函数接收四个参数,前一个值、当前值、项的索引、数组对象,这个函数的任何返回值都会作为第一个参数自动传给下一项。在该函数中,第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数为数组的第二项
console.log([1, 2, 3].reduce(function (prev, cur, index, array) {
return prev + cur
})
) //6
ES6
拓展运算符 ...
可以展开数组,将数组转换为参数序列。
console.log(...[1, 2, 3]) //1 2 3
遍历方式 for...of
for...of可以自定义遍历方式,而且这种遍历方式是for、for...in理解实现的
for (let item of [1, 2, 3]) {
console.log(item)
}
// 1
// 2
// 3
for (let item of [1, 2, 3].values()) {
console.log(item)
}
// 1
// 2
// 3
for (let item of [1, 2, 3].keys()) {
console.log(item)
}
// 0
// 1
// 2
for (let item of [1, 2, 3].entries()) {
console.log(item)
}
// [0, 1]
// [1, 2]
// [2, 3]
这里有一个值得注意的点,for...in循环也可以遍历数组中的每一项,但是用for...in循环遍历出来的数组的每一项会被转换为字符串型,而非原数据类型。
from()
可以将类似数组的对象和可遍历的对象转换为真正的数组,这里需要注意的是一定要给定length属性,否则为空数组。
var obj = {
0: 1,
1: 2,
2: 3,
length: 3
}
console.log(Array.from(obj)) // [1, 2, 3]
of()
of()总是会返回参数值组成的数组,如果没有参数,则返回空数组。
console.log(Array.of(1, 2, 3, 4)) // [1, 2, 3, 4]
console.log(Array.of()) // []
copyWithin(target, start, end)
在当前数组内部,将指定位置的成员,复制到其他位置,然后返回当前数组。target 从该位置开始替换数据,如果为负值,表示倒数,start 从该位置开始读取数据,默认为 0,如果为负值,表示从末尾开始计算,end 到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。会改变原数组。
console.log([1, 2, 3, 4, 5, 6].copyWithin(3, 0)) // [1, 2, 3, 1, 2, 3]
console.log([1, 2, 3, 4, 5, 6].copyWithin(-6, -3)) //[4, 5, 6, 4, 5, 6]
find() & findIndex()
find()用于找出第一个符合条件的数组,传入一个回调函数,数组的所有项执行该回调函数,直到找到第一个符合条件的项并返回该项,如果没有符合条件的项,则返回undefined。
console.log([1, 2, 3, 4, 5].find(function (i) {
return i > 3
})
) //4
findIndex()与find()类似,不同的是,findIndex()返回第一个符合条件的索引,如果没有符合条件的数组项,则返回-1。
console.log([1, 2, 3, 4, 5].find(function (i) {
return i > 3
})
) //3
fill(value,start,end)
使用给定值,填充一个数组,并返回填充后的数组。value 填充值,start 起始位置,end 结束位置。
console.log([1, 2, 3, 4, 5].fill(6, 0, 6)) //[6, 6, 6, 6, 6]
keys() & values() & entries()
这三个方法都用于遍历数组,并返回一个遍历器对象,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。在for...of中已经使用过这三个方法,所以在这里不做重复,只做补充。
entries()可以用如下两种方式获取键,值或数组形式的键值对。
for (var [index, elem] of [1, 2, 3].entries()) {
console.log(index, elem)
}
//0 1
//1 2
//2 3
for (var i of [1, 2, 3].entries()) {
console.log(i)
}
//[0, 1]
//[1, 2]
//[2, 3]
ES7
includes()
用于检测数组中是否包含给定的值,如果有则返回true,无则返回false。
console.log([1, 2, 3].includes(2)) //true
console.log([1, 2, 3].includes('2')) //false
这里有一个值得注意的点,includes()可以解决indexOf()对NaN的误判问题。
console.log([1, 2, NaN].indexOf(NaN)) //-1
console.log([1, 2, NaN].includes(NaN)) //true
ES10
flat() & flatMap()
flat()可以将嵌套的数组中的子数组取出并添加在原来的位置。在默认的情况下,该数组只取出第一层子数组,如果想取出多层,可以加一个参数来指定需要取出的层数。如果数组中有空位,flat()方法会跳过空位。
var arr = [1, 2, 3, [4, 5, 6, [7, 8, 9]]]
console.log(arr.flat()) //[1, 2, 3, 4, 5, 6, [7, 8, 9]]
console.log(arr.flat(2)) //[1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log([1, 2, , 4, 5].flat()) //[1, 2, 4, 5]
flatMap()可以对原数组的每一个成员执行一个回调函数然后对返回值组成的数组执行flat()方法,该方法返回一个新数组,不改变原数组。flatMap()只能展开一层数组,回调函数可以传入三个参数:currentValue 当前正在数组中处理的元素、index 数组中正在处理的当前元素的索引,array 被调用的 map 数组,thisArg,遍历函数 this 的指向
arr.flatMap(function callback(currentValue[, index[, array]]) {
// ...
}[, thisArg])
console.log([1, 2, 3].flatMap((x) => [x * 2])) //[2, 4, 6]
console.log([1, 2, 3].flatMap((x) => [[x * 2]])) //[[2], [4], [6]]
console.log([1, 2, 3, [4, 5, 6, [7, 8, 9]]].flatMap(function (i) {
return i * 2
})
) //[2, 4, 6, NaN]
结尾
本文只进行了JavaScript数组方法的基本使用总结,如果想要详细了解,建议翻阅红宝书,犀牛书或者ES6标准入门。如有不足或者错误的地方,还请指正。
下面推荐两篇JavaScript数组的一些技巧性操作。
参考资料
- 《JavaScript高级程序设计(第4版)》
- 《ES6标准入门(第3版)》