JavaScript 36个数组方法完整参数返回值表(附:已废弃或不推荐使用的数组方法)
本文系统整理了JavaScript数组方法,按"增删改查判"分类总结36个核心方法及其参数、返回值。
重点介绍了sort()、flatMap()等方法的特性和使用场景,对比了破坏性方法与非破坏性方法的差异。
同时指出已废弃或不推荐使用的数组模式,并推荐ES2023新增的toReversed()等非破坏性方法。
通过示例详细解析了flatMap()的数据处理优势,强调其在现代开发中的重要性。
本文可以看做是下列文章的升级版
关联阅读推荐
JavaScript 常用数组去重方法及性能对比(附:扩展运算符...总结)
JavaScript 字符串和数组方法总结(默写版)ES2023新增:toSorted(), toReversed(), toSpliced(), with()
类数组转数组的方法:Array.from() 和 扩展运算符 的区别(附:支持扩展运算符的类数组对象表)
JavaScript 36个数组方法完整参数返回值表
牢记五字真言 “增-删-改-查-判”
| 分类 | 方法 | 参数 | 返回值 |
| 增 | concat() | ...arrays: any[] | 新数组(合并后) |
| push() | ...elements: any[] | 新数组长度 | |
| unshift() | ...elements: any[] | 新数组长度 | |
| 删 | pop() | 无参数 | 被删除的元素 |
| shift() | 无参数 | 被删除的元素 | |
| slice() | start?: number, end?: number | 截取原数组的一部分,返回新数组 | |
| splice() | start: number, deleteCount?: number, ...items?: any[] | 添加/删除,返回被删除的元素组成的数组 | |
| 改(数组) | from() | arrayLike: any, mapFn?: (element, index) => any | 将类数组或可迭代对象转为数组 |
| of() | ...elements: any[] | 将一组参数转为数组 | |
| 改元素 | copyWithin() | target: number, start: number, end?: number | 复制部分数组到该数组中其他位置,不改变原数组长度,返回修改后的数组 |
| fill() | value: any, start?: number, end?: number | 数组填充,返回修改后的数组 | |
| 扁平 | flat() | depth?: number | 新数组(扁平后) |
| 归并 | reduce() | callback: (accumulator, current, index, array) => any, initialValue?: any | 累加结果 |
| reduceRight() | callback: (accumulator, current, index, array) => any, initialValue?: any | 累加结果 | |
| 排序 | sort() | compareFunction?: (a, b) => number | 排序后的原数组(默认升序) |
| reverse() | 无参数 | 反转后的原数组 | |
| 转字符串 | join() | separator?: string | string |
| 继承方法 | toString() | 无参数 | 返回表示指定数组及其元素的字符串 |
| toLocaleString() | 无参数 | 将数组元素转换为本地化的字符串表示形式。 | |
| valueOf() | 所有对象都继承自 Object 的方法之一 | 返回数组本身,而不是数组的字符串表示。 | |
| 查:怎么查(遍历) | forEach() | callback: (element, index, array) => void | undefined |
| 映射 | map() | callback: (element, index, array) => any | 新数组 |
| flatMap() | callback: (element, index, array) => any | 新数组(扁平后) | |
| 迭代 | keys() | 无参数 | Array Iterator |
| values() | 无参数 | Array Iterator | |
| entries() | 无参数 | Array Iterator | |
| 过滤 | filter() | callback: (element, index, array) => boolean | 新数组(过滤后) |
| 查什么(位置) | indexOf() | searchElement: any, fromIndex?: number | 索引位置或-1 |
| lastIndexOf() | searchElement: any, fromIndex?: number | 索引位置或-1 | |
| 查元素 | at() | index: number (支持负数) | 对应元素或undefined |
| find() | callback: (element, index, array) => boolean | 找到的元素或undefined | |
| findIndex() | callback: (element, index, array) => boolean | 索引位置或-1 | |
| 判 | isArray() | value: any | boolean |
| includes() | searchElement: any, fromIndex?: number | boolean | |
| some() | callback: (element, index, array) => boolean | boolean | |
| every() | callback: (element, index, array) => boolean | boolean |
参数类型速记表
| 参数类型 | 说明 | 常用方法 |
|---|---|---|
callback函数 |
(element, index, array) => any |
map, filter, forEach, find, some, every, reduce |
起始位置 |
start?: number |
slice, splice, indexOf, includes, copyWithin, fill |
搜索元素 |
searchElement: any |
indexOf, lastIndexOf, includes |
分隔符 |
separator?: string |
join |
深度 |
depth?: number |
flat |
比较函数 |
compareFunction?: (a, b) => number |
sort |
初始值 |
initialValue?: any |
reduce, reduceRight |
返回值类型分类表
| 返回值类型 | 方法 | 特点 |
|---|---|---|
| 新数组 | map, filter, slice, concat, flat, flatMap, from, of |
不改变原数组 |
| 原数组 | push, pop, shift, unshift, splice, sort, reverse, copyWithin, fill |
改变原数组 |
| boolean | includes, some, every, isArray |
判断结果 |
| 索引/元素 | indexOf, lastIndexOf, findIndex, find, at |
查找结果 |
| 数值 | push, unshift |
返回长度 |
| 字符串 | join, toString, toLocaleString |
字符串结果 |
| 迭代器 | keys, values, entries |
可迭代对象 |
| 累加结果 | reduce, reduceRight |
归并计算结果 |
| undefined | forEach |
无返回值 |
重要参数模式
// 1. 回调函数三件套 (元素, 索引, 数组)
arr.map((element, index, array) => { })
// 2. 起始位置 + 结束位置
arr.slice(start, end)
arr.fill(value, start, end)
// 3. 目标位置 + 源位置
arr.copyWithin(target, start, end)
JavaScript中已废弃或不推荐使用的数组方法
在 JavaScript 中,数组方法的“废弃”或“不推荐使用”通常分为两类:一类是已被标准标记为废弃的方法,另一类是虽未被废弃但因性能、副作用等问题不推荐使用的模式。同时,随着 ES2023 新方法的引入,一些老方法的使用场景也发生了变化。
📜 JavaScript 中不推荐使用的数组方法及相关模式
| 方法 / 模式 | 状态与问题描述 | 现代替代方案 |
|---|---|---|
Array.observe() / Array.unobserve() |
已过时 (Obsolete)。它们曾被用于异步观察数组的变化,但已被完全移除,无法使用-8。 | 使用 Proxy 对象来拦截和自定义对数组的操作,实现更灵活和强大的观察机制-8。 |
| 非标准数组通用方法 (如 Array.slice(myArr, ...), Array.forEach(myArr, ...)) |
已过时 (Obsolete)。这些方法曾试图将数组实例方法作为静态方法来调用,现已从所有浏览器中移除-8。 | 直接使用标准的实例方法,如 myArr.slice(...)、myArr.forEach(...)-8。 |
for...in 循环遍历数组 |
强烈不推荐。for...in 设计用于遍历对象的可枚举属性,而非数组元素。它会遍历出数组原型链上可能存在的其他属性,且遍历顺序不确定,可能导致意外结果-3-6。 |
- 使用 for...of 循环(推荐,可直接获取值)。- 使用 for 循环(性能好,可获取索引)。- 使用 forEach() 方法(函数式风格)-6。 |
reverse() |
虽未废弃,但需注意副作用。该方法会直接改变原数组。在 React、Vue 等注重状态不可变性的框架中,直接修改原数组容易引发难以追踪的bug-4。 | 使用 ES2023 引入的 toReversed() 方法。它返回一个新数组,原数组保持不变-4。 |
sort() |
虽未废弃,但需注意副作用。与 reverse() 类似,sort() 方法也会直接改变原数组,具有破坏性-4。 |
使用 ES2023 引入的 toSorted() 方法。它返回一个排序后的新数组,不影响原数组-4。 |
splice() |
虽未废弃,但需注意副作用。用于添加或删除数组中的元素,是直接修改原数组的典型方法-4。 | 使用 ES2023 引入的 toSpliced() 方法。它以非破坏性的方式执行相同的操作,返回修改后的新数组-4。 |
| 通过索引直接修改元素 (如 arr[index] = value) |
虽未废弃,但需注意副作用。这种操作方式同样会直接改变原数组,在不可变数据流中应谨慎使用-4。 | 使用 ES2023 引入的 with() 方法。它返回一个指定索引被替换为新值后的新数组副本-4。 |
| 过度链式调用 (如 arr.filter().map().slice()) |
不推荐(从性能角度)。每次调用都会创建并遍历新的中间数组,在处理超大规模数据时,会产生巨大的内存开销和性能损耗-7-9。 | - 对于性能敏感的场景,考虑使用 for 或 while 循环,将多次操作合并为一次遍历。- 使用 ES2025/2026 的迭代器助手(如 values().filter().map().take()),它们以懒执行的方式工作,不会创建中间数组,直到最终调用 toArray() 才生成结果-7。 |
💡 核心要点与总结
-
区分“废弃”与“不推荐”:像
Array.observe()这类是真正被标准移除的废弃功能。而reverse()、sort()这类是标准核心方法,并未废弃,但在现代应用(特别是使用 React、Vue 等框架)中,它们的破坏性(修改原数组) 特性被视为一种不推荐的做法-4。 -
拥抱非破坏性方法:ES2023 引入的
toReversed(),toSorted(),toSpliced(),with()是数组操作的未来趋势。它们让代码更可预测,尤其在状态管理中能有效避免副作用,提高代码的健壮性-4。 -
关注性能与可读性的平衡:对于大多数业务代码,
filter、map等方法足够清晰且性能良好,无需过度优化。但当你在处理成千上万甚至更大数据集的性能瓶颈时,就应该考虑使用传统的for循环或新兴的迭代器助手来避免不必要的中间数组开销-7-9。
sort()
1. sort()方法会改变原数组 ,而不是返回一个新数组。
2. 默认排序是将元素转换为字符串,然后比较它们的UTF-16代码单元值序列。
3. 对于数字排序,必须提供比较函数: (a, b) => a - b 用于升序, (a, b) => b - a 用于降序。
4. 比较函数应返回负数、零或正数,分别表示a在b之前、保持原顺序、a在b之后。
flatMap()方法使用示例详解
基本语法
array.flatMap(callback(currentValue, index, array), thisArg)
-
参数:映射函数
(element, index, array) => newValue -
返回值:新数组(先映射后扁平化一级)
1. 基础使用示例
示例1:数组元素展开
const arr = [1, 2, 3];
// 每个元素变成包含自身和加1的数组
const result = arr.flatMap(x => [x, x + 1]);
console.log(result); // [1, 2, 2, 3, 3, 4]
// 对比 map() 的效果
const mapResult = arr.map(x => [x, x + 1]);
console.log(mapResult); // [[1, 2], [2, 3], [3, 4]]
示例2:过滤并展开
const numbers = [1, 2, 3, 4, 5];
// 只处理偶数,并展开为多个元素
const result = numbers.flatMap(x => {
return x % 2 === 0 ? [x, x * 2] : [];
});
console.log(result); // [2, 4, 4, 8]
2. 实际应用场景
场景1:句子分词
const sentences = ["Hello world", "JavaScript is awesome", "Web development"];
// 将句子分割成单词并扁平化
const words = sentences.flatMap(sentence => sentence.split(' '));
console.log(words);
// ["Hello", "world", "JavaScript", "is", "awesome", "Web", "development"]
// 对比:使用 map() + flat() 的等价写法
const words2 = sentences.map(sentence => sentence.split(' ')).flat();
console.log(words2); // 相同结果
场景2:数据清洗和转换
const data = [
{ name: "Alice", tags: ["js", "web"] },
{ name: "Bob", tags: ["python", "data"] },
{ name: "Charlie", tags: [] }
];
// 提取所有标签并扁平化
const allTags = data.flatMap(person => person.tags);
console.log(allTags); // ["js", "web", "python", "data"]
// 自动过滤空数组
const emptyFiltered = data.flatMap(person => person.tags || []);
console.log(emptyFiltered); // ["js", "web", "python", "data"]
场景3:矩阵操作
const matrix = [
[1, 2],
[3, 4],
[5, 6]
];
// 矩阵转置的思路(简化版)
const flattened = matrix.flatMap(row => row);
console.log(flattened); // [1, 2, 3, 4, 5, 6]
// 每个元素乘以2并展开
const doubled = matrix.flatMap(row => row.map(x => x * 2));
console.log(doubled); // [2, 4, 6, 8, 10, 12]
3. 高级应用示例
示例1:嵌套数组处理
const nestedArrays = [[1], [2, 3], [4, 5, 6]];
// 展开并给每个元素添加索引信息
const result = nestedArrays.flatMap((subArray, index) =>
subArray.map(value => ({ value, originalIndex: index }))
);
console.log(result);
// [
// {value: 1, originalIndex: 0},
// {value: 2, originalIndex: 1},
// {value: 3, originalIndex: 1},
// {value: 4, originalIndex: 2},
// {value: 5, originalIndex: 2},
// {value: 6, originalIndex: 2}
// ]
示例2:数据分组展开
const students = [
{ name: "Alice", scores: [85, 90] },
{ name: "Bob", scores: [78, 82] },
{ name: "Charlie", scores: [95] }
];
// 将每个学生和分数配对展开
const scoreDetails = students.flatMap(student =>
student.scores.map(score => ({
student: student.name,
score: score
}))
);
console.log(scoreDetails);
// [
// {student: "Alice", score: 85},
// {student: "Alice", score: 90},
// {student: "Bob", score: 78},
// {student: "Bob", score: 82},
// {student: "Charlie", score: 95}
// ]
示例3:条件性展开
const products = [
{ name: "Laptop", categories: ["electronics", "computers"] },
{ name: "Book", categories: ["education"] },
{ name: "Phone", categories: ["electronics", "communication"] }
];
// 只展开电子类产品的分类
const electronicCategories = products.flatMap(product =>
product.categories.includes("electronics")
? product.categories
: []
);
console.log(electronicCategories);
// ["electronics", "computers", "electronics", "communication"]
4. 与相关方法对比
flatMap() vs map() + flat()
const arr = [1, 2, 3];
// 这三种写法等价
const result1 = arr.flatMap(x => [x, x * 2]);
const result2 = arr.map(x => [x, x * 2]).flat();
const result3 = [].concat(...arr.map(x => [x, x * 2]));
console.log(result1); // [1, 2, 2, 4, 3, 6]
console.log(result2); // [1, 2, 2, 4, 3, 6]
console.log(result3); // [1, 2, 2, 4, 3, 6]
性能考虑
// flatMap() 通常比 map().flat() 性能更好
// 因为只需要遍历一次数组
const largeArray = Array.from({ length: 10000 }, (_, i) => i);
// 使用 flatMap(推荐)
console.time('flatMap');
const result1 = largeArray.flatMap(x => [x, x + 1]);
console.timeEnd('flatMap');
// 使用 map + flat
console.time('mapFlat');
const result2 = largeArray.map(x => [x, x + 1]).flat();
console.timeEnd('mapFlat');
5. 注意事项
注意1:只扁平化一级
const arr = [1, 2, 3];
// flatMap 只扁平化一级
const result = arr.flatMap(x => [[x, x * 2]]);
console.log(result); // [[1, 2], [2, 4], [3, 6]] - 仍然是嵌套数组
// 需要多级扁平化时
const deepResult = arr.flatMap(x => [[x, x * 2]]).flat();
console.log(deepResult); // [1, 2, 2, 4, 3, 6]
注意2:返回非数组值
const arr = [1, 2, 3];
// 如果回调函数返回非数组值,会自动包装成数组
const result = arr.flatMap(x => x * 2);
console.log(result); // [2, 4, 6] - 相当于 map(x => x * 2)
// 等价于
const result2 = arr.flatMap(x => [x * 2]);
console.log(result2); // [2, 4, 6]
总结
flatMap() 的核心优势:
-
一次性操作:映射 + 扁平化一级
-
代码简洁:避免
map().flat()的链式调用 -
自动过滤:返回空数组时自动过滤掉
-
性能优化:通常比分开操作性能更好
使用场景:数据转换、文本处理、矩阵操作、条件性展开等需要同时进行映射和扁平化的场景。
Array.prototype.reduce()
Array.prototype.reduce() 是 JavaScript 中最强大的数组方法之一,用于将数组“缩减”为单个值(如求和、累加对象、扁平化等)。
它的签名如下:
1arr.reduce(callback(accumulator, currentValue, index, array), initialValue)
1. 参数详解
A. 回调函数 callback (必填)
这是每次迭代时执行的函数,它接收 4 个参数(通常只使用前两个):
accumulator(累加器):- 累积的结果。
- 它的值取决于上一次回调函数的返回值。
- 如果是第一次调用:
- 若提供了
initialValue,则它是initialValue。 - 若未提供
initialValue,则它是数组的第一个元素。
- 若提供了
currentValue(当前值):- 当前正在处理的数组元素。
- 如果是第一次调用且未提供
initialValue,则它是数组的第二个元素。
index(索引,可选):- 当前元素的索引。
- 注意:如果未提供
initialValue,第一次回调时的索引是1(因为第 0 个被当作累加器了);如果提供了initialValue,第一次回调时的索引是0。
array(原数组,可选):- 调用
reduce的原始数组。
- 调用
B. initialValue (可选)
- 作用: 作为第一次调用回调函数时
accumulator的初始值。 - 重要性: 强烈建议始终提供此参数,以避免空数组报错和逻辑歧义。
2. initialValue 的行为差异 (核心重点)
是否提供 initialValue 会完全改变 reduce 的执行逻辑:
表格
| 场景 | accumulator初始值 |
currentValue起始位置 |
循环次数 | 空数组[]的行为 |
|---|---|---|---|---|
提供 initialValue |
initialValue |
索引 0 (第一个元素) |
数组长度次 | 返回 initialValue (不报错) |
不提供 initialValue |
数组索引 0 的元素 |
索引 1 (第二个元素) |
数组长度 - 1 次 | 抛出 TypeError |
3. 代码示例
场景一:数字求和 (推荐写法)
const numbers = [1, 2, 3, 4];
// 提供 initialValue (0)
const sum = numbers.reduce((acc, curr) => {
console.log(`累加器: ${acc}, 当前值: ${curr}`);
return acc + curr;
}, 0);
// 执行过程:
// 1. acc=0, curr=1 -> return 1
// 2. acc=1, curr=2 -> return 3
// 3. acc=3, curr=3 -> return 6
// 4. acc=6, curr=4 -> return 10
console.log(sum); // 10
场景二:如果不提供 initialValue
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, curr) => {
return acc + curr;
});
// 没有第二个参数
// 执行过程:
// 1. acc=1 (数组第0项), curr=2 (数组第1项) -> return 3
// 2. acc=3, curr=3 -> return 6
// 3. acc=6, curr=4 -> return 10
console.log(sum); // 10 (结果一样,但逻辑不同)
场景三:空数组的陷阱 (必须提供 initialValue)
const emptyArr = [];
// ❌ 错误:不提供 initialValue,空数组会报错
try {
emptyArr.reduce((acc, curr) => acc + curr);
} catch (e) {
console.error(e.message);
// 输出: "Reduce of empty array with no initial value"
}
// ✅ 正确:提供 initialValue,安全返回默认值
const safeSum = emptyArr.reduce((acc, curr) => acc + curr, 0);
console.log(safeSum); // 0
场景四:处理对象数组 (典型用例)
将数组转换为对象,必须提供初始对象作为 initialValue。
const users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 35 }
];
// 需求:计算总年龄
const totalAge = users.reduce((acc, user) => {
return acc + user.age;
}, 0); // 初始值为 0
console.log(totalAge); // 90
// 需求:按名字分组 (初始值为空对象 {})
const grouped = users.reduce((acc, user) => {
acc[user.name] = user.age;
return acc;
}, {});
console.log(grouped);
// { Alice: 25, Bob: 30, Charlie: 35 }
4. 总结最佳实践
- 永远提供
initialValue:- 防止空数组报错。
- 明确代码意图(例如求和从 0 开始,拼接字符串从
""开始,构建对象从{}开始)。 - 确保类型安全(避免累加器在第一次迭代时意外变成数组中的某个复杂对象)。
- 明确参数名:
- 不要只用
(a, b),使用(acc, curr)或(total, item)等具有语义的名称。
- 不要只用
- 注意返回值:
reduce的最终结果是最后一次回调函数的返回值。务必确保你的回调函数在所有路径下都return了正确的值。
更多推荐


所有评论(0)