🔥JavaScript 数组全解析:从「到底是不是数组?」到「方法全家桶」一篇搞定

"把数组玩透,才能把前端写活。"

本文首发于作者博客,持续更新,建议收藏。


目录

  1. 判断:我到底是不是数组?
  2. 静态方法:不需要实例就能用的工具箱
  3. 会改变原数组的方法(9 个)
  4. 不会改变原数组的方法(10+ 个)
  5. ES2023+ 的新玩具:toSorted / toReversed / toSpliced
  6. 高频手写题 & 易错点
  7. 一张思维导图带走全部记忆

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 状态不可变、算法题手写等),即可 掌握全部精髓。

相关推荐
vaelcy几秒前
Cursor入门级教程,下载、安装、AI核心功能简介
前端·ai编程·cursor
Jolyne_24 分钟前
树节点key不唯一的勾选、展开状态的处理思路
前端·算法·react.js
饺子不放糖25 分钟前
workspace:你真的会用吗?
前端
饺子不放糖28 分钟前
dependencies vs devDependencies:别再傻傻分不清,你的 package.json 可能早就"胖"了!
前端
岁忧32 分钟前
(LeetCode 面试经典 150 题) 104. 二叉树的最大深度 (深度优先搜索dfs)
java·c++·leetcode·面试·go·深度优先
Kevin@wust34 分钟前
axios的封装
前端·vue
teeeeeeemo36 分钟前
Ajax、Axios、Fetch核心区别
开发语言·前端·javascript·笔记·ajax
Juchecar37 分钟前
TypeScript对 null/undefined/==/===/!=/!== 等概念的支持,以及建议用法
javascript
柏成42 分钟前
基于 pnpm + monorepo 的 Qiankun微前端解决方案(内置模块联邦)
前端·javascript·面试
唐诗1 小时前
VMware Mac m系列安装 Windws 11,保姆级教程
前端·后端·github