ES6 为数组新增了许多实用方法,让数组操作更加便捷。
Array.from()#
将类数组或可迭代对象转为真正的数组。
基本用法#
// 类数组对象const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }Array.from(arrayLike) // ['a', 'b', 'c']
// 字符串Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
// SetArray.from(new Set([1, 2, 2, 3])) // [1, 2, 3]
// MapArray.from( new Map([ ['a', 1], ['b', 2], ])) // [['a', 1], ['b', 2]]
// NodeListconst divs = document.querySelectorAll('div')Array.from(divs) // [div, div, div, ...]映射函数#
第二个参数是映射函数,类似 map:
Array.from([1, 2, 3], (x) => x * 2) // [2, 4, 6]
// 等价于Array.from([1, 2, 3]).map((x) => x * 2)
// 生成数字序列Array.from({ length: 5 }, (_, i) => i) // [0, 1, 2, 3, 4]Array.from({ length: 5 }, (_, i) => i + 1) // [1, 2, 3, 4, 5]
// 生成随机数组Array.from({ length: 5 }, () => Math.random())实际应用#
// 数组去重function unique(arr) { return Array.from(new Set(arr))}unique([1, 2, 2, 3, 3, 3]) // [1, 2, 3]
// 创建二维数组function create2DArray(rows, cols, value = 0) { return Array.from({ length: rows }, () => Array.from({ length: cols }, () => value) )}create2DArray(3, 4, 0)// [[0,0,0,0], [0,0,0,0], [0,0,0,0]]
// 生成字母表const alphabet = Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i))// ['A', 'B', 'C', ..., 'Z']
// Unicode 字符正确处理Array.from('𠮷') // ['𠮷'](正确处理 32 位字符)'𠮷'.split('') // ['\uD842', '\uDFB7'](错误)Array.of()#
创建包含指定元素的数组,解决 new Array() 的怪异行为:
// new Array 的问题new Array(3) // [empty × 3](单个数字创建指定长度的空数组)new Array(3, 4) // [3, 4]new Array('3') // ['3']
// Array.of 行为一致Array.of(3) // [3]Array.of(3, 4) // [3, 4]Array.of('3') // ['3']Array.of(undefined) // [undefined]Array.of() // []find() 和 findIndex()#
查找符合条件的元素或索引:
const users = [ { id: 1, name: '张三' }, { id: 2, name: '李四' }, { id: 3, name: '王五' },]
// find 返回元素const user = users.find((u) => u.id === 2)console.log(user) // { id: 2, name: '李四' }
// 找不到返回 undefinedusers.find((u) => u.id === 100) // undefined
// findIndex 返回索引users.findIndex((u) => u.id === 2) // 1
// 找不到返回 -1users.findIndex((u) => u.id === 100) // -1与 indexOf 的区别:
// indexOf 使用 === 比较,无法查找 NaN;[NaN].indexOf(NaN) // -1
// find 可以使用自定义条件;[NaN].find((x) => Number.isNaN(x)) // NaN;[NaN].findIndex((x) => Number.isNaN(x)) // 0
// indexOf 只能查找值,find 可以查找对象属性const arr = [{ id: 1 }, { id: 2 }]arr.indexOf({ id: 1 }) // -1(对象引用不同)arr.find((item) => item.id === 1) // { id: 1 }findLast() 和 findLastIndex()#
ES2023 新增,从数组末尾开始查找:
const numbers = [1, 2, 3, 2, 1]
// 从前往后找第一个numbers.find((n) => n === 2) // 2(索引 1)numbers.findIndex((n) => n === 2) // 1
// 从后往前找第一个numbers.findLast((n) => n === 2) // 2(索引 3)numbers.findLastIndex((n) => n === 2) // 3
// 实际应用:找最后一个满足条件的元素const logs = [ { time: '10:00', type: 'info' }, { time: '10:05', type: 'error' }, { time: '10:10', type: 'info' }, { time: '10:15', type: 'error' },]
logs.findLast((log) => log.type === 'error')// { time: '10:15', type: 'error' }fill()#
用固定值填充数组:
// 基本用法;[1, 2, 3].fill(0) // [0, 0, 0]
// 指定起始和结束位置;[1, 2, 3, 4, 5].fill(0, 1, 3) // [1, 0, 0, 4, 5]
// 创建并填充new Array(5).fill(0) // [0, 0, 0, 0, 0]
// 🔶 注意:对象填充是同一个引用const arr = new Array(3).fill({ x: 0 })arr[0].x = 1console.log(arr) // [{ x: 1 }, { x: 1 }, { x: 1 }]
// 正确做法const arr2 = Array.from({ length: 3 }, () => ({ x: 0 }))arr2[0].x = 1console.log(arr2) // [{ x: 1 }, { x: 0 }, { x: 0 }]copyWithin()#
在数组内部复制元素:
// copyWithin(target, start, end)// target: 复制到的位置// start: 复制源的起始位置// end: 复制源的结束位置(不包含)
;[1, 2, 3, 4, 5].copyWithin(0, 3)// [4, 5, 3, 4, 5](从位置3开始复制到位置0)
;[1, 2, 3, 4, 5].copyWithin(0, 3, 4)// [4, 2, 3, 4, 5](只复制一个元素)
;[1, 2, 3, 4, 5].copyWithin(-2, 0, 2)// [1, 2, 3, 1, 2](负数从末尾计算)entries()、keys()、values()#
返回遍历器对象:
const arr = ['a', 'b', 'c']
// keys() 返回索引for (const index of arr.keys()) { console.log(index) // 0, 1, 2}
// values() 返回值for (const value of arr.values()) { console.log(value) // 'a', 'b', 'c'}
// entries() 返回 [索引, 值]for (const [index, value] of arr.entries()) { console.log(index, value) // 0 'a', 1 'b', 2 'c'}
// 转为数组;[...arr.entries()] // [[0, 'a'], [1, 'b'], [2, 'c']]includes()#
判断数组是否包含某元素:
;[1, 2, 3].includes(2) // true;[1, 2, 3].includes(4) // false
// 可以检测 NaN;[1, NaN, 3].includes(NaN) // true;[1, NaN, 3].indexOf(NaN) // -1(indexOf 无法检测)
// 指定起始位置;[1, 2, 3].includes(1, 1) // false(从索引1开始查找);[1, 2, 3].includes(1, -3) // true(负数从末尾计算)空位处理#
ES6 明确将数组空位转为 undefined:
// ES5 方法对空位处理不一致;[, , ,].forEach((x) => console.log(x)) // 不输出(跳过空位);[, , ,].map((x) => 1) // [empty × 3](跳过空位)
// ES6 方法统一处理为 undefinedArray.from([, , ,]) // [undefined, undefined, undefined];[...[, , ,]] // [undefined, undefined, undefined];[, , ,].fill(1) // [1, 1, 1]
// for...of 也会遍历空位for (const x of [, , ,]) { console.log(x) // undefined, undefined, undefined}实战应用#
数组分组#
function groupBy(arr, fn) { return arr.reduce((groups, item) => { const key = fn(item) ;(groups[key] = groups[key] || []).push(item) return groups }, {})}
const users = [ { name: '张三', age: 25 }, { name: '李四', age: 30 }, { name: '王五', age: 25 },]
groupBy(users, (u) => u.age)// { 25: [{...}, {...}], 30: [{...}] }数组分块#
function chunk(arr, size) { return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => arr.slice(i * size, i * size + size) )}
chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]数组打乱#
function shuffle(arr) { const result = [...arr] for (let i = result.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)) ;[result[i], result[j]] = [result[j], result[i]] } return result}
shuffle([1, 2, 3, 4, 5]) // [3, 1, 5, 2, 4](随机)数组去重(保持顺序)#
function unique(arr, key) { if (key) { const seen = new Set() return arr.filter((item) => { const k = item[key] if (seen.has(k)) return false seen.add(k) return true }) } return [...new Set(arr)]}
unique([1, 2, 2, 3]) // [1, 2, 3]unique([{ id: 1 }, { id: 2 }, { id: 1 }], 'id') // [{ id: 1 }, { id: 2 }]方法汇总#
| 方法 | 作用 | 返回值 |
|---|---|---|
| Array.from() | 类数组转数组 | 新数组 |
| Array.of() | 创建数组 | 新数组 |
| find() | 查找元素 | 元素或 undefined |
| findIndex() | 查找索引 | 索引或 -1 |
| findLast() | 从后查找元素 | 元素或 undefined |
| findLastIndex() | 从后查找索引 | 索引或 -1 |
| fill() | 填充数组 | 修改后的原数组 |
| copyWithin() | 内部复制 | 修改后的原数组 |
| includes() | 是否包含 | boolean |
| entries() | 键值对迭代器 | Iterator |
| keys() | 键迭代器 | Iterator |
| values() | 值迭代器 | Iterator |
这些方法让数组操作更加直观和便捷,熟练掌握可以写出更简洁的代码。