数组,是 javascript 中很常见的对象,工作中经常用到,所以它有很多个Api,详细见MDN Array。 有不少 API 可以达到部份相同效果,因此有不少开发同学会混淆,比如查找元素时,使用遍历API。 很有必要详细了解下他的API ,合理使用API ,减少不必要的性能问题。
Array 提供了很多 Api ,大概可以分为4类: 创建Api,访问Api,修改Api,遍历Api
创建Api:
创建Api : 通过其他值,创建一个新的数组
[]: 通过字面量创建数组。Object.create(Array.prototype): 创建的是类数组对象,并不是数组,不能通过isArray方法
Array: 构造器方法 ,new Array,Array: 效果一样- 一个参数 , 且是数字 n : 返回一个长度是 n 的,全是空元素的数组
- 其他 :将参数转换成数组, 跟
of功能一样
of: 将可变参数,转换成数组,返回一个新数组Array.of('a', 'b', 'c') // ['a','b','c']from: 从可迭代对象,或者类数组对象拷贝,返回一个新数组Array.from([1, 2, 3], (x) => x + x) // [2,4,6] Array.from('hello') // ['h','e','l','l','0'] Array.from({length: 100},(_,j)=>j) // 快速创建一个包含 0-99 的数组isArray: 判断一个值是否是数组。arr.constructor.name === 'Array'判断是否数组不谨慎。
访问Api:
访问Api : 访问数组的元素,进行操作,原数组不发生变化
返回新数组
concat: 把数组元素 和 其他数组元素合并,返回新数组slice: 获取数组 start 到 end 一段元素,包含 start 不包含 end ,返回新数组- 参数
start: 起始位置, 如果负数,就是倒数位置,等价len + start - 参数
end: 结束为止,不传,就是最后, 如果起始位置大于结束为止,返回空数组
const arr = [1,2,3,4,5] arr.slice(-2) // [4,5] arr.slice(-2,2) // []- 参数
flat: 将数组元素中的数组压平,降维度, 返回新数组- 参数
depth: 深度,压平的深度
// 可以用 toString 的特性,将数组转换成 字符串,在 split 成数组 [0, 1, 2, [3, 4,[5,6,7,[8,[9]]]]].toString().split(',') // ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']- 参数
flatMap: 调用 map() 方法之后在 调用 flat(1) ,arr.map(...args).flat()
返回迭代器
keys: 返回数组元素索引的 迭代器 对象values: 返回数组元素值的 迭代器 对象Symbol.iterator: 返回数组数组元素值 迭代器对象 ,arr.[Symbol.iterator]()与value返回对象相同entries: 返回数组键值对[key,value]的 迭代器 对象
判断数组元素
include: 判断数组是否包含一个元素, 返回 booleanindexOf: 从头开始判断元素在数组中的第一个出现位置,返回索引,没有返回 -1, 查询方向 -->- 参数
fromIndex: 查询的起始位置, 如果负数,就是倒数位置,等价len + start
- 参数
lastIndexOf: 从尾开始判断元素在数组中的第一个出现位置,返回索引,没有返回 -1 , 查询方向 <--- 参数
fromIndex: 查询的起始位置, 如果负数,就是倒数位置,等价len + start
- 参数
返回字符串
join: 将数组元素用分隔符链接,返回字符串toString: 返回用来表示数组的字符串, 其实是调用join方法,如果join不可用, 返回[object Array]toLocaleString: 返回用来表示数组的字符串,数组的每个元素,都需要调用其本身的toLocaleString转化
修改Api:
修改Api : 对原数组进行修改,包括修改数组元素,修改数组结构,原数组会发生变化
修改数组元素
sort: 默认:对数组元素转换为字符串 ,按照 UTF-16 码元值升序排序。 返回原数组- 参数 compareFn : 定义排序的函数, 返回一个数字, 负数->升序 正数->降序 0->保持原样 NaN->位置不稳定
const arr = [1, 30, 4, 21, 100]; arr.sort((a,b)=>a-b) // 升序 // a[1] = 4reverse: 反转数组,返回原数组const arr = [1, 30, 4, 21, 100]; arr.reverse() // a[2] = 21 // 实现一个数组反转 Array.prototype.reverseArr = function () { const len = this.length; for (let i = 0; i <= len / 2; i++) { [this[i], this[len - 1 - i]] = [this[len - 1 - i], this[i]]; } return this; } arr.reverse() // a[2] = 30copyWithin: 用数组的一部分,拷贝值原数组的位置, 返回原数组。const arr = [1, 2, 3, 4, 5] arr.copyWithin(1,2,4) // 把索引 2-4 的数据,拷贝至索引 1 的位置 。 是拷贝,不是移动 // arr = [1, 3, 4, 4, 5]
修改数组结构
push: 数组最后添加一个元素,返回数组长度pop: 删除数组最后一个元素,返回该元素unshift: 数组最前添加一个元素,返回数组长度shift: 删除数组最前一个元素,返回元素splice: 从某个位置删除指定长度元素,或者用其他元素替换- 参数
start: 开始位置 - 参数
count: 长度, 不传参数,就是到数组末尾 - 参数
...item: 多个参数,用来替换的元素列表
const arr = [1,2,3,4,5] arr.splice(1,2,3,4,5) // 从 index:1 开始,删除 2 个元素,用 3,4,5 来填充 // arr : [1, 3, 4, 5, 4, 5]- 参数
fill: 从 start 到 end 填充 元素- 参数
start: 不传就是 0, 开始 - 参数
end: 不传就是len-1,结尾
- 参数
修改Api的非修改版本
toReversed: 反转数组,返回新数组,原数组不变toSorted: 数组排序,返回新数组,原数组不变toSpliced: 数组删除或者替换部份元素,返回新数组,原数组不变
遍历Api
遍历Api : 遍历原数组,对其中的元素进行 修改,查询,判断 等操作。 原数组不发生变化
forEach: 对数组的元素依次执行给定的函数。 函数接受三个参数,元素,索引,数组对象。arr.forEach((element, index, array) => { xxx })map: 对数组的元素依次执行给定的函数, 将返回值创建一个新数组。 函数接受三个参数,元素,索引,数组对象。const newArr = arr.map((element, index, array) => { return xxx })every: 对数组的元素依次执行给定的函数,所有的值执行函数的结果都返回true, 则返回true, 否则返回false。 空数组不管函数结果返回如何,结果都是trueconst newBoolean = arr.every((element, index, array) => { return xxx })some: 对数组的元素依次执行给定的函数,所有的值执行函数的结果都返回false, 则返回false, 否则返回true。 空数组不管函数结果返回如何,结果都是falseconst newBoolean = arr.some((element, index, array) => { return xxx })filter: 对数组的元素依次执行给定的函数,将返回值为true的元素,组成一个新数组const newArr = arr.filter((element, index, array) => { return xxx })find: 对数组的元素依次执行给定的函数,返回第一个结果为true的元素, 没有就返回undefinedconst element = arr.find((element, index, array) => { return xxx })findIndex: 对数组的元素依次执行给定的函数,返回第一个结果为true的元素索引, 没有就返回-1const elementIndex = arr.find((element, index, array) => { return xxx })findLast: 与find类似,依次执行函数顺序相反findLastIndex: 与findIndex类似,依次执行函数顺序相反reduce: 给定初始值,将初始值 和 数组元素 执行函数 返回结果,作为下一次的初始值,循环执行函数, 返回最终执行函数结果const result = arr.reduce( (lastResult, element, index , array ) => { return newResult } initialValue, )- 参数
initialValue: 如果没传,就是数组第一个元素。
- 参数
reduceRight: 与reduce类似,执行函数的方向不同, 从数组末尾开始执行。const result = arr.reduceRight( (lastResult, element, index , array ) => { return newResult } initialValue, )- 参数
initialValue: 如果没传,就是数组最后一个元素。 - 链式调用:细心的人已经发现了,
reduce,reduceRight是一个链式调用 。我们可以利用reduce,reduceRight来实现一个compose函数。const compose = function (...fns) { return fns.reduceRight((a, b) => { return (...argvs) => { a(b(...argvs)); }; }); }; const fun1 = ()=> console.log(1) const fun2 = ()=> console.log(2) const fun3 = ()=> console.log(3) const composedFunction = compose(fun1, fun2, fun3) // composedFunction() 依次执行 fun1,fun2 fun3 // 也可以用 reduce 实现一个反向执行的 compose
- 参数
总结
Array 的 Api 是真的多,也是因为日常用到数组的地方实在太多,进行需要对数组进行各种各样的操作。 在使用之前一定要清楚 Api 的作用,有几个点要时刻明确
- 是否对原数组进行修改, 还是产生新的数组
- 是否需要遍历原数组,还是仅仅过滤一些值,
forEach,maporfilter? every和some很好用 ,判断整个数组是否符合一些条件slice和splice别搞混,slice传入2个索引返回新数组 ,splice传入索引+ 长度 对原数组进行修改- 链式调用记住
reduce push+pop是 栈push+shift是 队列