"把数组玩透,才能把前端写活。"
本文首发于作者博客,持续更新,建议收藏。
目录
- 判断:我到底是不是数组?
- 静态方法:不需要实例就能用的工具箱
- 会改变原数组的方法(9 个)
- 不会改变原数组的方法(10+ 个)
- ES2023+ 的新玩具:toSorted / toReversed / toSpliced
- 高频手写题 & 易错点
- 一张思维导图带走全部记忆
1. 判断:到底是不是数组?
方式 | 代码 | 结果 | 说明 |
---|---|---|---|
instanceof |
[] instanceof Array |
✅ true | 只能判断「由 Array 构造函数创建」的对象 |
Array.isArray |
Array.isArray([]) |
✅ true | 推荐!能识别 iframe / window 跨上下文 |
Object.prototype.toString |
Object.prototype.toString.call([]) |
[object Array] |
通用,可区分 Array , Arguments , NodeList |
constructor |
[].constructor === Array |
✅ true | 可伪造,不安全 |
结论:生产环境统一用
Array.isArray
,面试题再补toString
彰显深度。
2. 静态方法
方法 | 作用 | 示例 |
---|---|---|
Array.from |
类数组 / 可迭代 → 真数组 | Array.from({length:3}, (_,i)=>i) // [0,1,2] |
Array.of |
避免 new Array(3) 的坑 |
Array.of(3) // [3] |
Array.isArray |
见第 1 节 |
3. 会改变原数组的方法(9 个)
口诀:「推(push) 波(pop) 前(shift) 后(unshift) 排(sort) 反(reverse) 切(splice) 填(fill) 拷(copyWithin)」
方法 | 作用 | 返回 | 示例 |
---|---|---|---|
push |
尾部追加 | 新长度 | arr.push(4) |
pop |
尾部删除 | 被删元素 | arr.pop() |
shift |
头部删除 | 被删元素 | arr.shift() |
unshift |
头部追加 | 新长度 | arr.unshift(0) |
splice |
万能增删改 | 被删数组 | arr.splice(1,2,'x','y') |
sort |
字典序排序 | 原数组 | arr.sort((a,b)=>a-b) |
reverse |
反转 | 原数组 | arr.reverse() |
fill |
填充 | 原数组 | new Array(5).fill(0) |
copyWithin |
内部拷贝 | 原数组 | [1,2,3,4].copyWithin(0,2) ➜ [3,4,3,4] |
4. 不会改变原数组的方法
4.1 查询 & 过滤
includes
(ES2016)indexOf / lastIndexOf
find / findIndex / findLast(ES2022)
filter
4.2 转换
map
flat
/flatMap
(ES2019)
4.3 归约
reduce / reduceRight
4.4 遍历
forEach
(注意:无法break
)
4.5 切片
slice(start?, end?)
4.6 连接
concat
4.7 字符串化
join
5. ES2023+ 新玩具:非变异版本
新方法 | 语义 | 与原方法关系 |
---|---|---|
toSorted |
排序 | 返回新数组,同 slice().sort() |
toReversed |
反转 | 返回新数组 |
toSpliced |
增删改 | 返回新数组 |
with(index, value) |
替换单元素 | 函数式写法 |
有了它们,React 状态更新再也不用手动
...arr
拷贝。
6. 高频手写题 & 易错点
6.1 手写 flat
js
function flat(arr, depth = 1) {
return depth > 0
? arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? flat(cur, depth - 1) : cur), [])
: arr.slice();
}
6.2 不要信任 sort 的稳定性
- Chrome v8 在数组长度 ≤ 10 时插入排序,>10 时快排 → 老版本不稳定
- 解决:
arr.map((v,i)=>({v,i})).sort((a,b)=>a.v-b.v||a.i-b.i).map(o=>o.v)
6.3 稀疏数组的坑
js
new Array(3).map(() => 1) // [empty × 3] 不会执行
[,,,].forEach(console.log) // 无输出
改用 Array.from({length:3}, () => 1)
。
7. 思维导图(文字版)
perl
Array
├─ 判断
│ ├─ Array.isArray
│ └─ Object.prototype.toString
├─ 静态方法
│ ├─ Array.from
│ └─ Array.of
├─ 改变自身
│ ├─ push / pop / shift / unshift
│ ├─ splice / sort / reverse
│ └─ fill / copyWithin
├─ 不改变自身
│ ├─ 查询:includes find filter ...
│ ├─ 转换:map flat flatMap
│ ├─ 归约:reduce reduceRight
│ └─ 工具:slice join concat
└─ ES2023+
├─ toSorted / toReversed / toSpliced
└─ with
结语
数组方法虽多,但记住「是否改变原数组」这条主线,再结合实际场景(React 状态不可变、算法题手写等),即可 掌握全部精髓。