一、核心概念
JavaScript 数组的内置方法是开发中最常用的工具,也是面试高频考点。核心关注点包括:
- 功能:方法的核心作用
- 返回值:执行后返回什么(新数组 / 单个值 / undefined)
- 可变性:是否修改原数组(mutability)
JavaScript 数组的核心内置方法,涵盖迭代遍历(map、filter、reduce 等)、修改原数组(splice、push 等)及返回新数组(slice、concat 等)三大类。重点解析了各方法的返回值、可变性及适用场景,通过基础与实战示例对比了 map 与 forEach、slice 与 splice 的区别,并补充了 reduce 初始值的影响及手动实现思路。旨在帮助开发者提升代码可读性,避免状态管理中的副作用问题,并应对高频面试考点。
JavaScript 数组的内置方法是开发中最常用的工具,也是面试高频考点。核心关注点包括:
| 分类 | 包含方法 | 核心特征 |
|---|---|---|
| 迭代遍历方法 | forEach、map、filter、reduce、some、every | 遍历数组元素并执行逻辑 |
| 修改原数组(Mutator) | push、pop、shift、unshift、splice、sort、reverse | 直接改变原数组,有副作用 |
| 返回新数组(Non-mutating) | map、filter、concat、slice | 原数组不变,返回新数组 |
| 查找判断方法 | find、findIndex、includes、indexOf | 查找元素或判断存在性 |
工作中最常使用。
基础示例:
const numbers = [1, 4, 9];
const doubles = numbers.map(num => num * 2);
console.log(doubles); // [2, 8, 18]
console.log(numbers); // [1, 4, 9](原数组不变)
实战示例:对象数组属性提取
const users = [
{ id: 1, name: '张三', age: 20 },
{ id: 2, name: '李四', age: 25 },
{ id: 3, name: '王五', age: 30 }
];
// 提取所有用户名
const userNames = users.map(user => user.name);
console.log(userNames); // ["张三", "李四", "王五"]
// 批量修改属性(返回新对象)
const adultUsers = users.map(user => ({ ...user, isAdult: user.age >= 18 }));
console.log(adultUsers[0]); // { id: 1, name: '张三', age: 20, isAdult: true }
基础示例:
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction'];
const longWords = words.filter(word => word.length > 6);
console.log(longWords); // ["exuberant", "destruction"]
[].filter(Boolean) //可以过滤掉 null
实战示例:多条件过滤
const products = [
{ name: '手机', price: 2999, category: '数码', stock: 50 },
{ name: '耳机', price: 199, category: '数码', stock: 0 },
{ name: 'T 恤', price: 99, category: '服饰', stock: 100 },
{ name: '键盘', price: 499, category: '数码', stock: 30 }
];
// 筛选:数码类、价格<500、有库存的商品
const validProducts = products.filter(p => p.category === '数码' && p.price < 500 && p.stock > 0 );
console.log(validProducts);
arr.reduce((acc, cur, idx, arr) => {}, initialValue)
acc:累加器(上一次回调的返回值 / 初始值)cur:当前元素initialValue:可选,累加器初始值(推荐必传)基础示例:求和
const array = [1, 2, 3, 4];
const sum = array.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 10
实战示例 1:数组转对象(按 ID 映射)
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
];
// 转换为 { 1: { id:1, name:'张三' }, 2: { ... } }
const userMap = users.reduce((acc, cur) => {
acc[cur.id] = cur;
return acc;
}, {});
console.log(userMap[2]); // { id: 2, name: '李四' }
实战示例 2:扁平嵌套数组
const nestedArr = [1, [2, [3, 4], 5], 6];
const flatArr = nestedArr.reduce((acc, cur) => {
return acc.concat(Array.isArray(cur) ? cur.reduce((a, c) => a.concat(c), []) : cur);
}, []);
console.log(flatArr); // [1, 2, 3, 4, 5, 6]
实战示例 3:分组统计
const scores = [
{ name: '张三', subject: '数学', score: 90 },
{ name: '张三', subject: '语文', score: 85 },
{ name: '李四', subject: '数学', score: 88 },
{ name: '李四', subject: '语文', score: 92 }
];
// 按姓名分组,统计总分
const scoreSum = scores.reduce((acc, cur) => {
if (!acc[cur.name]) { acc[cur.name] = 0; }
acc[cur.name] += cur.score;
return acc;
}, {});
console.log(scoreSum); // { 张三:175, 李四:180 }
示例:
const fruits = ['苹果', '香蕉', '橙子'];
// 打印每个元素
fruits.forEach((fruit, index) => {
console.log(`第${index+1}个水果:${fruit}`);
});
// 注意:forEach 无法中断遍历(break 无效),需用 some/every 替代
示例:
const numbers = [10, 20, 30, 35];
// some:是否有元素>30
const hasBigNum = numbers.some(num => num > 30);
console.log(hasBigNum); // true
// every:是否所有元素>15
const allBigNum = numbers.every(num => num > 15);
console.log(allBigNum); // false(10 不满足)
// 实战:判断是否有已过期的订单
const orders = [
{ id: 1, expired: false },
{ id: 2, expired: true },
{ id: 3, expired: false }
];
const hasExpired = orders.some(order => order.expired);
console.log(hasExpired); // true
arr.splice(start, deleteCount, item1, item2...)
start:起始索引(负数表示从末尾开始)deleteCount:删除的元素数量(0 则不删除)item...:要插入的元素示例 1:插入元素
const months = ['Jan', 'March', 'April', 'June'];
// 索引 1 的位置,删除 0 个,插入'Feb'
const removed = months.splice(1, 0, 'Feb');
console.log(months); // ["Jan", "Feb", "March", "April", "June"]
console.log(removed); // [](无删除)
示例 2:删除元素
const arr = [1, 2, 3, 4, 5];
// 索引 2 的位置,删除 2 个元素
const deleted = arr.splice(2, 2);
console.log(arr); // [1, 2, 5]
console.log(deleted); // [3, 4]
示例 3:替换元素
const arr = ['a', 'b', 'c', 'd'];
// 索引 1 的位置,删除 1 个,插入'x'和'y'
arr.splice(1, 1, 'x', 'y');
console.log(arr); // ["a", "x", "y", "c", "d"]
| 方法 | 功能 | 返回值 | 示例 |
|---|---|---|---|
| push | 尾部添加元素 | 新数组长度 | const arr = [1,2]; arr.push(3); // arr=[1,2,3],返回 3 |
| pop | 尾部删除元素 | 被删除的元素 | const arr = [1,2,3]; arr.pop(); // arr=[1,2],返回 3 |
| unshift | 头部添加元素 | 新数组长度 | const arr = [2,3]; arr.unshift(1); // arr=[1,2,3],返回 3 |
| shift | 头部删除元素 | 被删除的元素 | const arr = [1,2,3]; arr.shift(); // arr=[2,3],返回 1 |
示例:
// sort 自定义排序(数字升序)
const numbers = [10, 2, 25, 5];
numbers.sort((a, b) => a - b);
console.log(numbers); // [2, 5, 10, 25]
// reverse 反转
const arr = [1, 2, 3];
arr.reverse();
console.log(arr); // [3, 2, 1]
arr.slice(start, end)(start 包含,end 不包含,负数表示末尾)示例:
const arr = [1, 2, 3, 4, 5];
// 截取索引 1 到 3(不包含 3)
const slice1 = arr.slice(1, 3);
console.log(slice1); // [2, 3]
// 截取最后 2 个元素
const slice2 = arr.slice(-2);
console.log(slice2); // [4, 5]
// 浅拷贝整个数组
const copyArr = arr.slice();
copyArr[0] = 10;
console.log(arr); // [1, 2, 3, 4, 5](原数组不变)
示例:
const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = arr1.concat(arr2, 5);
console.log(arr3); // [1, 2, 3, 4, 5]
console.log(arr1); // [1, 2](原数组不变)
| 维度 | map | forEach |
|---|---|---|
| 返回值 | 新数组 | undefined |
| 用途 | 数据转换,需返回新数组 | 执行操作(打印、调 API),无需返回值 |
| 链式调用 | 支持(map().filter()) | 不支持(返回 undefined) |
| 维度 | slice | splice |
|---|---|---|
| 可变性 | 不修改原数组 | 修改原数组 |
| 功能 | 截取数组片段 | 增删改数组元素 |
| 参数 | slice(start, end) | splice(start, deleteCount, ...items) |
| 返回值 | 截取的新数组 | 被删除的元素数组 |
| 场景 | 有 initialValue | 无 initialValue |
|---|---|---|
| 空数组 | 返回 initialValue | 抛出 TypeError |
| 非空数组 | acc 初始值 = initialValue,从第一个元素开始遍历 | acc 初始值 = 第一个元素,从第二个元素开始遍历 |
示例:
// 有 initialValue(推荐)
[1,2,3].reduce((acc, cur) => acc + cur, 0); // 6(acc 初始=0,遍历 1→2→3)
// 无 initialValue
[1,2,3].reduce((acc, cur) => acc + cur); // 6(acc 初始=1,遍历 2→3)
// 空数组 + 无 initialValue → 报错
// [].reduce((acc, cur) => acc + cur); // Uncaught TypeError
state.arr.push(1)),需用非变异方法([...state.arr, 1]);const copy = [...arr])再操作。[1,,3].map(x => x*2) → [2,,6]);// 手动实现 map
Array.prototype.myMap = function(callback) {
const newArr = [];
for (let i = 0; i < this.length; i++) {
if (i in this) { // 处理稀疏数组
newArr[i] = callback(this[i], i, this);
}
}
return newArr;
};
// 手动实现 reduce
Array.prototype.myReduce = function(callback, initialValue) {
let acc = initialValue;
let startIndex = 0;
// 无 initialValue 时,acc 初始化为第一个元素
if (initialValue === undefined) {
if (this.length === 0) throw new TypeError('空数组无初始值');
acc = this[0];
startIndex = 1;
}
for (let i = startIndex; i < this.length; i++) {
if (i in this) {
acc = callback(acc, this[i], i, this);
}
}
return acc;
};

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online