JavaScript数组的常用方法,然后列出常见的问题。
注意:数组方法可以分为以下几类:变更方法(修改原数组)、访问方法(不修改原数组)、迭代方法等。
一、数组常用方法
- 变更方法(修改原数组):
push():末尾添加一个或多个元素,返回新长度
pop():删除最后一个元素,返回该元素
shift():删除第一个元素,返回该元素
unshift():开头添加一个或多个元素,返回新长度
splice():删除、插入或替换元素,返回被删除的元素组成的数组
sort():排序,默认按字符串Unicode码点排序
reverse():反转数组
- 访问方法(不修改原数组):
concat():合并数组,返回新数组
slice(start, end):截取数组,返回新数组
join(separator):将数组连接成字符串
indexOf():返回指定元素第一次出现的索引
lastIndexOf():返回指定元素最后一次出现的索引
includes():判断是否包含某元素
- 迭代方法(不修改原数组,但回调函数可以修改):
forEach():遍历数组,无返回值
map():对每个元素调用回调,返回新数组
filter():过滤,返回满足条件的元素组成的新数组
reduce():从左到右累加
reduceRight():从右到左累加
some():判断是否至少有一个元素满足条件
every():判断是否所有元素都满足条件
find():返回第一个满足条件的元素
findIndex():返回第一个满足条件的元素的索引
- ES6+ 新增方法:
Array.from():将类数组对象或可迭代对象转换为数组
Array.of():将一组值转换为数组
fill():填充数组
copyWithin():在数组内部复制元素
flat():数组扁平化
flatMap():先map再flat(1)
二、常见题
数组去重
数组扁平化(多维数组转一维)
数组排序(包括自定义排序)
数组方法的实现(如实现map、filter、reduce等)
数组的深拷贝
数组和类数组的区别及转换
数组的遍历方法比较(for、forEach、for...in、for...of)
使用reduce实现复杂功能(如实现map、filter等)
数组的常见操作(合并、截取、反转等)
数组的迭代方法的应用(如some、every、find等)
三、常被问的题(示例)
- 数组去重的多种实现方式
使用Set
使用filter+indexOf
使用reduce
使用对象键值对
- 数组扁平化(多维数组转一维)
递归
使用flat方法
使用reduce递归
使用扩展运算符
手写数组方法(如map、filter、reduce等)
数组排序(如按对象的某个属性排序)
数组的深拷贝(考虑多层嵌套)
类数组转数组(arguments、NodeList等)
使用数组方法解决复杂问题(如求交集、并集、差集)
数组遍历的性能比较
数组的哪些方法会改变原数组,哪些不会
数组的空位处理(如[1,,3])
下面我们详细展开一些常见题的解答:
JavaScript 数组方法大全及高频题解析
一、数组核心方法分类
| 类型 | 方法 | 特点 |
|---|---|---|
| 增删改 |
push()/pop()/shift()/unshift()/splice()
|
修改原数组 |
| 转换 |
join()/toString()/Array.from()/Array.of()
|
生成新格式 |
| 截取 |
slice()/concat()
|
返回新数组 |
| 查找 |
indexOf()/lastIndexOf()/find()/findIndex()/includes()
|
返回位置或元素 |
| 遍历 |
forEach()/map()/filter()/reduce()/some()/every()
|
迭代处理 |
| 排序 |
sort()/reverse()
|
修改原数组 |
| ES6+ |
flat()/flatMap()/fill()/copyWithin()
|
新增功能 |
二、高频题及解析
1. map() vs forEach() 区别?
const arr = [1, 2, 3];
// map:返回新数组
const mapped = arr.map(x => x * 2); // [2, 4, 6]
// forEach:无返回值
arr.forEach(x => console.log(x)); // 1, 2, 3
-
map():返回新数组,适合数据转换 -
forEach():仅遍历,无返回值
2. 实现数组去重(3种方法)
// 方法1:Set(ES6最简单)
const unique1 = [...new Set([1,2,2,3])]; // [1,2,3]
// 方法2:filter + indexOf
const unique2 = [1,2,2,3].filter(
(item, idx, arr) => arr.indexOf(item) === idx
);
// 方法3:reduce
const unique3 = [1,2,2,3].reduce(
(acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []
);
3. reduce() 高级用法
// 1. 数组求和
[1,2,3].reduce((sum, n) => sum + n, 0); // 6
// 2. 二维数组转对象
const arr = [['name','Alice'], ['age',30]];
arr.reduce((obj, [key, val]) => ({...obj, [key]: val}), {});
// 3. 实现数组扁平化
const flatten = arr => arr.reduce(
(flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []
);
4. 数组排序陷阱
// 数字排序错误做法
[10, 5, 100].sort(); // [10, 100, 5](按字符串Unicode排序)
// 正确做法
[10, 5, 100].sort((a, b) => a - b); // [5, 10, 100]
// 对象数组排序
const users = [
{name: 'Alice', age: 30},
{name: 'Bob', age: 25}
];
users.sort((a, b) => a.age - b.age); // 按年龄升序
5. 数组方法实现原理(手写)
// 手写 map()
Array.prototype.myMap = function(callback) {
const result = [];
for (let i = 0; i < this.length; i++) {
result.push(callback(this[i], i, this));
}
return result;
};
// 手写 filter()
Array.prototype.myFilter = function(callback) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};
6. 数组空位处理
const arr = [1, , 3]; // 空位
// ES5 方法跳过空位
arr.forEach(x => console.log(x)); // 1, 3
// ES6 方法视空位为 undefined
Array.from(arr); // [1, undefined, 3]
[...arr]; // [1, undefined, 3]
7. 数组扁平化(多维转一维)
const arr = [1, [2, [3, [4]]]];
// 方法1:flat(Infinity)
arr.flat(Infinity); // [1,2,3,4]
// 方法2:reduce + 递归
function flatten(arr) {
return arr.reduce(
(acc, val) => acc.concat(Array.isArray(val) ? flatten(val) : val), []
);
}
// 方法3:toString(仅数字数组)
arr.toString().split(',').map(Number);
8. 类数组转真数组
// DOM元素列表
const nodeList = document.querySelectorAll('div');
// 转换方法
const arr1 = Array.from(nodeList);
const arr2 = [...nodeList];
const arr3 = [].slice.call(nodeList);
9. 数组性能对比题
// 创建10万元素数组
const largeArray = Array(100000).fill(0);
// 测试 for vs forEach vs for...of
console.time('for');
for (let i = 0; i < largeArray.length; i++) {} // 最快
console.timeEnd('for');
console.time('forEach');
largeArray.forEach(() => {}); // 次之
console.timeEnd('forEach');
console.time('for...of');
for (const item of largeArray) {} // 最慢
console.timeEnd('for...of');
10. 数组方法链式调用
const data = [
{id: 1, value: 10, active: true},
{id: 2, value: 20, active: false},
{id: 3, value: 30, active: true}
];
// 链式处理:激活状态对象 → 值翻倍 → 求和
const result = data
.filter(item => item.active)
.map(item => item.value * 2)
.reduce((sum, val) => sum + val, 0); // 80
三、数组核心考点总结
-
方法特性:
- 哪些方法修改原数组(
sort,splice等) - 哪些返回新数组(
map,filter等)
- 哪些方法修改原数组(
-
性能优化:
- 大数据集避免链式调用(中间数组浪费内存)
- 遍历优先用
for循环
-
ES6+ 特性:
-
Array.from()处理类数组 -
flat()多维数组扁平化 - 空位处理差异
-
-
函数式编程:
-
map/filter/reduce组合应用 - 避免副作用(纯函数)
-
-
手写实现:
- 常考
map、filter、reduce实现 - 理解迭代器协议
- 常考
建议:遇到数组问题先明确需求 - 需要返回新数组还是修改原数组?数据规模如何?是否需要考虑兼容性?掌握核心方法的特性组合使用能解决90%的数组相关问题。