1. 创建和转换方法
1.1 Array.from()
Array.from() 是 JavaScript 用于将类数组对象或可迭代对象转换为真正数组的方法。
Array.from(arrayLike, mapFn, thisArg)
arrayLike(必填):类数组对象(如 arguments、NodeList、HTMLCollection)或可迭代对象(如 Set、Map、字符串)。 mapFn(可选):映射函数,类似 Array.map(),用于对每个元素进行转换。 thisArg(可选):执行 mapFn 时的 this 绑定。
// 将类数组对象转换为数组
const arrayFromString = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
let divs = document.querySelectorAll('div'); // `NodeList`(类数组)
let divArray = Array.from(divs);
console.log(divArray); // 真正的数组
function example() {
console.log(arguments); // Arguments(3) [1, 2, 3]
let argsArray = Array.from(arguments);
console.log(argsArray); // [1, 2, 3] 真正的数组
}
example(1, 2, 3);
// 带映射函数的转换
const numbers = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]
// 给字符串转换为 Unicode 码点
let unicodeArr = Array.from('hello', char => char.charCodeAt(0));
console.log(unicodeArr); // [104, 101, 108, 108, 111]
// 转换对象属性值
let obj = { a: 1, b: 2, c: 3 };
let values = Array.from(Object.values(obj), v => v * 2);
console.log(values); // [2, 4, 6]
// 实际应用:转换 DOM 元素集合
const links = Array.from(document.querySelectorAll('a'));
// 生成数字序列
const sequence = Array.from({ length: 5 }, (_, i) => i + 1); // [1, 2, 3, 4, 5]
// 将可迭代对象转换为数组
// 转换 Set
let set = new Set([1, 2, 3, 4, 4]);
let arr = Array.from(set);
console.log(arr); // [1, 2, 3, 4] (去重)
// 转换 Map
let map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]);
let arr = Array.from(map);
console.log(arr); // [[1, 'a'], [2, 'b'], [3, 'c']]
1.2 Array.of()
// 创建新数组
const arr1 = Array.of(7); // [7]
const arr2 = Array.of(1, 2, 3); // [1, 2, 3]
// 对比传统 Array 构造函数
const arr3 = new Array(7); // [empty × 7]
const arr4 = Array.of(7); // [7]
2. 查找和搜索方法
2.1 find() 和 findIndex()
const users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 3, name: 'Bob' }
];
// find() - 返回第一个满足条件的元素
const user = users.find(user => user.id === 2);
console.log(user); // { id: 2, name: 'Jane' }
// findIndex() - 返回第一个满足条件的元素的索引
const index = users.findIndex(user => user.name === 'Bob');
console.log(index); // 2
2.2 findLast() 和 findLastIndex()
const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
// findLast() - 从后向前查找第一个满足条件的元素
const lastFour = numbers.findLast(num => num === 4);
console.log(lastFour); // 4 (第二个4)
// findLastIndex() - 从后向前查找第一个满足条件的元素的索引
const lastFourIndex = numbers.findLastIndex(num => num === 4);
console.log(lastFourIndex); // 5
2.3 includes()
const fruits = ['apple', 'banana', 'orange'];
// 检查数组是否包含某个元素
console.log(fruits.includes('banana')); // true
console.log(fruits.includes('grape')); // false
// 从指定位置开始搜索
console.log(fruits.includes('apple', 1)); // false
// 实际应用:条件判断
function handleFruit(fruit) {
if(['apple', 'banana', 'orange'].includes(fruit)) {
// 处理水果
}
}
3. 转换和映射方法
3.1 map()
map() 方法用于创建一个新数组,其元素是通过对原数组中的每个元素调用提供的回调函数计算得到的。
array.map(callback(element, index, array), thisArg);
callback(必填):回调函数,接收三个参数: element(当前元素):正在处理的数组项。 index(索引,可选):当前元素的索引。 array(原数组,可选)。 thisArg(可选):执行 callback 时的 this 值。 🔹 map() 不会修改原数组,而是返回一个新的数组。
const numbers = [1, 2, 3, 4];
// 基本映射 数组元素翻倍 map() 不会修改 numbers,它返回一个新数组。
const doubled = numbers.map(x => x * 2); // [2, 4, 6, 8]
// 对象转换 提取对象数组中的某个属性
const users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
];
const names = users.map(user => user.name); // ['John', 'Jane']
// 带索引的映射
const indexed = numbers.map((num, index) => ({
value: num,
index: index
}));
// 生成新对象数组
let people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 }
];
//生成新对象数组 map() 适用于不修改原对象,而是创建新对象。
let updatedPeople = people.map(person => ({
...person,
age: person.age + 1
}));
console.log(updatedPeople);
/*
[
{ name: "Alice", age: 26 },
{ name: "Bob", age: 31 }
]
*/
// map() + join() 生成字符串
let words = ["Hello", "World"];
let sentence = words.map(word => word.toLowerCase()).join(" ");
console.log(sentence);
// "hello world"
// map() + flat() 当 map() 返回嵌套数组时,可用 flat() 扁平化:
let numbers = [1, 2, 3];
let result = numbers.map(num => [num, num * 2]).flat();
console.log(result);
// [1, 2, 2, 4, 3, 6]
//等效于:
console.log(numbers.flatMap(num => [num, num * 2]));
🔹 map() 适用于 创建新数组,不改变原数组 数据转换、提取、格式化 比 forEach() 更适用于返回数据
3.2 flatMap()
flatMap() 方法用于先映射(map()),再扁平化(flat(1)),适用于一对多映射的场景,避免嵌套数组的产生。
array.flatMap(callback(element, index, array), thisArg);
flatMap() 等价于:
array.map(callback).flat(1);
但 flatMap() 只会展开一层,不能指定 depth。
const sentences = ['hello world', 'goodbye moon'];
// 展平并映射
const words = sentences.flatMap(str => str.split(' '));
console.log(words); // ['hello', 'world', 'goodbye', 'moon']
// 实际应用:处理嵌套数据
const orders = [
{ items: ['apple', 'banana'] },
{ items: ['orange'] }
];
const allItems = orders.flatMap(order => order.items);
// ['apple', 'banana', 'orange']
// 过滤 null 或 undefined
let data = ["apple", null, "banana", undefined, "cherry"];
let filtered = data.flatMap(item => item ? [item] : []);
console.log(filtered);
// ["apple", "banana", "cherry"]
// flatMap() 可以用于去除 null 或 undefined 的元素。
flatMap() vs map()
flatMap() 适用于 一对多映射,避免嵌套数组 比 map().flat(1) 更简洁 适合拆分字符串、提取数据
4. 过滤和筛选方法
4.1 filter()
const numbers = [1, 2, 3, 4, 5, 6];
// 基本过滤
const evenNumbers = numbers.filter(x => x % 2 === 0);
console.log(evenNumbers); // [2, 4, 6]
// 对象数组过滤
const users = [
{ name: 'John', age: 25 },
{ name: 'Jane', age: 17 },
{ name: 'Bob', age: 30 }
];
const adults = users.filter(user => user.age >= 18);
4.2 slice()
array.slice(start, end);
start(可选):开始索引(包含)。 如果省略,默认从 0 开始。 如果为负数,表示从数组末尾开始(-1 代表最后一个元素)。 end(可选):结束索引(不包含)。 如果省略,则默认到数组末尾。 如果为负数,表示从数组末尾计算。 注意:slice() 不会修改原数组,而是返回一个新数组。
const fruits = ['apple', 'banana', 'orange', 'grape', 'kiwi'];
// 提取部分数组
console.log(fruits.slice(1, 3)); // ['banana', 'orange']
let arr = [1, 2, 3, 4, 5];
let subArr = arr.slice(1, 4); // 提取索引 1 到 3(不包括 4)
console.log(subArr); // [2, 3, 4]
// 复制数组
const copy = fruits.slice();
let arr = [1, 2, 3, 4, 5];
let copy = arr.slice(); // 复制整个数组
console.log(copy); // [1, 2, 3, 4, 5]
// 获取最后几个元素 使用负索引
const last3 = fruits.slice(-3); // ['orange', 'grape', 'kiwi']
let arr = [1, 2, 3, 4, 5];
console.log(arr.slice(-3)); // [3, 4, 5] // 从倒数第 3 个开始到末尾
console.log(arr.slice(1, -1)); // [2, 3, 4] // 从索引 1 开始到倒数第 1 个(不包括)
console.log(arr.slice(-4, -1));// [2, 3, 4] // 从倒数第 4 个开始到倒数第 1 个(不包括)
5. 数组修改方法
5.1 splice()
splice() 是 JavaScript 数组的一个强大方法,用于删除、替换或插入数组中的元素。**它会直接修改原数组,**并返回被删除的元素组成的数组。
array.splice(start, deleteCount, item1, item2, ..., itemN)
start:必填,表示修改的起始索引(从 0 开始)。 deleteCount:可选,表示删除的元素个数。 如果 deleteCount 为 0,则不会删除元素。 如果省略 deleteCount,则会删除从 start 到数组末尾的所有元素。 item1, item2, ..., itemN:可选,要插入到 start 位置的新元素(如果有)。
const months = ['Jan', 'March', 'April', 'June'];
// 插入元素
months.splice(1, 0, 'Feb'); // 在索引1处插入
console.log(months); // ['Jan', 'Feb', 'March', 'April', 'June']
let arr = [1, 2, 5];
arr.splice(2, 0, 3, 4); // 在索引 2 位置插入 3 和 4
console.log(arr); // [1, 2, 3, 4, 5]
// 删除元素
months.splice(4, 1); // 删除索引4的元素
console.log(months); // ['Jan', 'Feb', 'March', 'April']
let arr = [1, 2, 3, 4, 5];
let removed = arr.splice(2, 2); // 从索引 2 开始删除 2 个元素
console.log(arr); // [1, 2, 5]
console.log(removed); // [3, 4]
// 替换元素
months.splice(2, 1, 'March-new'); // 替换索引2的元素
let arr = [1, 2, 99, 4, 5];
arr.splice(2, 1, 3); // 用 3 替换索引 2 的元素 99
console.log(arr); // [1, 2, 3, 4, 5]
slice() vs splice()
5.2 fill()
array.fill(value, start, end);
value(必填):要填充的值。 start(可选):开始索引(包含),默认是 0。 end(可选):结束索引(不包含),默认是 array.length
fill() 的特点 ✅ 修改原数组(不像 map() 生成新数组)。 ✅ 支持负索引(从数组末尾计算)。 ✅ 不能用于动态生成不同值(用 map() 更合适)。
// 填充整个数组
const array1 = new Array(3).fill(0); // [0, 0, 0]
// 填充部分数组
const numbers = [1, 2, 3, 4];
numbers.fill(0, 1, 3); // [1, 0, 0, 4]
let arr = [1, 2, 3, 4, 5];
arr.fill(9, 1, 4); // 索引 1 到 3(不包括 4)填充 9
console.log(arr); // [1, 9, 9, 9, 5]
//使用负索引
let arr = [1, 2, 3, 4, 5];
arr.fill(7, -3, -1); // 从倒数第 3 个到倒数第 1 个填充 7
console.log(arr); // [1, 2, 7, 7, 5]
// 创建矩阵
const matrix = Array(3).fill().map(() => Array(4).fill(0));
6. 数组排序方法
6.1 sort()
array.sort(compareFunction);
compareFunction(可选):用于定义排序规则的比较函数。 如果省略,默认按 Unicode 码点顺序排序(会导致数字排序异常)。 如果提供,它应该是一个函数 compare(a, b): 返回负数(a - b < 0):a 排在 b 前面。 返回正数(a - b > 0):b 排在 a 前面。 返回 0:顺序不变。
// 基本排序 默认排序(按 Unicode 排序)
const fruits = ['banana', 'apple', 'orange'];
fruits.sort(); // ['apple', 'banana', 'orange']
// 数字排序
const numbers = [10, 2, 5, 1, 9];
numbers.sort((a, b) => a - b); // [1, 2, 5, 9, 10] 升序
numbers.sort((a, b) => b - a); // 降序排序
//数字排序(⚠️ 默认排序可能错误)
let numbers = [10, 1, 21, 2];
numbers.sort();
console.log(numbers); // [1, 10, 2, 21] ❌(因为按字符串 Unicode 排序)
// 对象排序
let people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 20 },
{ name: "Charlie", age: 30 }
];
// 按年龄升序排序
people.sort((a, b) => a.age - b.age);
console.log(people);
/*
[
{ name: "Bob", age: 20 },
{ name: "Alice", age: 25 },
{ name: "Charlie", age: 30 }
]
*/
6.2 reverse()
const array = [1, 2, 3, 4, 5];
array.reverse(); // [5, 4, 3, 2, 1]
// 实际应用:创建倒序数组
const countdown = Array.from({length: 5}, (_, i) => i + 1).reverse();
// [5, 4, 3, 2, 1]
sort() 与 reverse()
let arr = [3, 1, 4, 1, 5];
arr.sort((a, b) => a - b).reverse(); // 先升序,再反转降序
console.log(arr); // [5, 4, 3, 1, 1]
7. 数组归约方法
reduce() 方法用于对数组中的每个元素执行回调函数,并将其结果汇总成单个值。
array.reduce(callback(accumulator, currentValue, index, array), initialValue);
callback:回调函数,接收四个参数: accumulator(累加器):累积计算的结果(上一次回调的返回值)。 currentValue(当前元素):正在处理的数组元素。 index(索引,可选):当前元素的索引(从 0 开始)。 array(原数组,可选)。 initialValue(可选):累加器的初始值,如果省略,则数组的第一个元素作为初始值,从第二个元素开始计算。
7.1 reduce()
const numbers = [1, 2, 3, 4, 5];
// 求和
const sum = numbers.reduce((acc, curr) => acc + curr, 0); // 15
// 计算数组元素的乘积
let product = [1, 2, 3, 4].reduce((acc, cur) => acc * cur, 1);
console.log(product); // 24
// 找到数组中的最大值
let numbers = [10, 5, 20, 8];
let max = numbers.reduce((acc, cur) => (cur > acc ? cur : acc), numbers[0]);
console.log(max); // 20
// 计算平均值
let numbers = [10, 20, 30, 40];
let average = numbers.reduce((acc, cur, _, arr) => acc + cur / arr.length, 0);
console.log(average); // 25
// 数组转对象 按属性统计元素个数
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana'];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
// { apple: 2, banana: 2, orange: 1 }
// or 计算对象数组中某个字段的总和
let items = [
{ name: "Apple", price: 10 },
{ name: "Banana", price: 5 },
{ name: "Cherry", price: 8 }
];
let totalPrice = items.reduce((acc, item) => acc + item.price, 0);
console.log(totalPrice); // 23
// 链式操作
const result = numbers
.filter(x => x % 2 === 0)
.map(x => x * 2)
.reduce((acc, curr) => acc + curr, 0);
// 数组去重
let numbers = [1, 2, 2, 3, 4, 4, 5];
let uniqueNumbers = numbers.reduce((acc, cur) => {
if (!acc.includes(cur)) acc.push(cur);
return acc;
}, []);
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]
reduce() vs map() vs filter()
let numbers = [1, 2, 3, 4, 5];
// 使用 map():元素翻倍
let doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// 使用 filter():筛选偶数
let evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]
// 使用 reduce():求和
let sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 15
7.2 reduceRight() 反向归纳
// 从右到左归约
const array = ['1', '2', '3', '4', '5'];
const result = array.reduceRight((acc, curr) => acc + curr);
console.log(result); // "54321"
// 实际应用:构建嵌套对象
const paths = ['user', 'profile', 'name'];
const nestedObj = paths.reduceRight((value, key) => ({
[key]: value
}), 'John');
// { user: { profile: { name: 'John' } } }
8. 数组迭代方法
8.1 forEach()
array.forEach(callback(currentValue, index, array));
callback(必填):回调函数,接收三个参数: currentValue(当前元素):正在处理的数组项。 index(索引,可选):当前元素的索引值。 array(原数组,可选)。 forEach() 不会返回值,它只是对数组的每个元素执行 callback 逻辑。
const items = ['item1', 'item2', 'item3'];
// 基本迭代
items.forEach((item, index) => {
console.log(\`\${index}: \${item}\`);
});
// 实际应用:批量DOM操作
document.querySelectorAll('button').forEach(button => {
button.addEventListener('click', handleClick);
});
forEach() 不能中断 forEach() 不能使用 break 或 return 来终止循环,只能通过 try...catch 或 throw 进行间接中断。
let numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => {
if (num === 3) return; // ❌ 不能跳过循环
console.log(num);
});
// 输出:
// 1
// 2
// 4
// 5 (不会跳过 3)
解决方案:使用 some() 或 for...of
numbers.some(num => {
if (num === 3) return true; // ✅ 终止遍历
console.log(num);
});
// 输出:
// 1
// 2
forEach() 可以修改原数组
let numbers = [1, 2, 3];
numbers.forEach((num, index, arr) => {
arr[index] = num * 2;
});
console.log(numbers); // [2, 4, 6]
但 不能使用 forEach() 删除或添加元素:
let numbers = [1, 2, 3, 4];
numbers.forEach((num, index, arr) => {
if (num === 2) arr.splice(index, 1); // ❌ 会导致索引错乱
});
console.log(numbers); // 可能不是预期结果
建议使用 filter() 删除元素:
let filtered = numbers.filter(num => num !== 2);
console.log(filtered); // [1, 3, 4]
forEach() vs 其他遍历方法
8.2 every() 和 some()
every() 方法用于测试数组中的所有元素是否都满足指定条件,如果所有元素都满足,则返回 true,否则返回 false。
array.every(callback(element, index, array), thisArg);
callback(必填):回调函数,接收三个参数: element(当前元素):正在处理的数组项。 index(索引,可选):当前元素的索引。 array(原数组,可选)。 thisArg(可选):指定 callback 运行时的 this 值。 🔹 every() 逻辑
如果所有元素都满足条件,返回 true。 只要有一个元素不满足,立即返回 false,不会继续遍历剩余元素。 如果 every() 遇到一个 false,就会立即停止遍历 🔹 every() 适用于: 所有元素都需要满足某个条件 短路优化:一旦发现 false,立即停止遍历 比 forEach() 更高效,适用于布尔检查
const numbers = [1, 2, 3, 4, 5];
// every() - 检查所有元素是否满足条件
const allPositive = numbers.every(num => num > 0); // true
// 检查数组是否全是偶数
const allEven = numbers.every(num => num % 2 === 0); // false
// some() - 检查是否存在满足条件的元素
// 检查数组中是否有偶数
const hasEven = numbers.some(num => num % 2 === 0); // true
const hasNegative = numbers.some(num => num < 0); // false
// 检查是否存在大于 10 的元素
let numbers = [2, 5, 8, 12, 4];
let hasLargeNumber = numbers.some(num => num > 10);
console.log(hasLargeNumber); // true
some() 方法用于测试数组中是否至少有一个元素满足指定条件。如果至少有一个元素满足,则返回 true,否则返回 false。
array.some(callback(element, index, array), thisArg);
callback(必填):回调函数,接收三个参数: element(当前元素):正在处理的数组项。 index(索引,可选):当前元素的索引。 array(原数组,可选)。 thisArg(可选):指定 callback 运行时的 this 值。 🔹 some() 逻辑 如果至少有一个元素满足条件,返回 true,并立即停止遍历(短路机制)。 如果所有元素都不满足,返回 false。
every() vs some()
9. 数组展平方法
flat() 方法用于扁平化多维数组,即将嵌套的数组展开成一维或指定层级的数组。
array.flat(depth);
depth(可选):指定要扁平化的深度,默认值为 1。 1:展开一层(默认)。 Infinity:展开所有层。 n:展开 n 层。 🔹 flat() 不会修改原数组,它会返回一个新的数组。
9.1 flat()
const nested = [1, [2, 3], [4, [5, 6]]];
// 一级展平
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]
// 多级展平
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]
// 完全展平
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6]
// 实际应用:处理嵌套评论
const comments = [
{ id: 1, replies: [
{ id: 2, replies: [
{ id: 3, replies: [] }
]}
]}
];
const allComments = comments.flatMap(comment => [
comment,
...comment.replies.flatMap(reply => [
reply,
...reply.replies
])
]);
flat() 还会自动移除数组中的空项:
let arr = [1, 2, , 4, [5, , 7]];
console.log(arr.flat());
// [1, 2, 4, 5, 7]
空位 , 被移除,而 undefined 和 null 不会被移除。
flat() + map() flat() 和 map() 可以一起使用,等效于 flatMap():
let arr = [1, 2, 3];
let result = arr.map(x => [x * 2]).flat();
console.log(result);
// [2, 4, 6]
等效于
let arr = [1, 2, 3];
console.log(arr.flatMap(x => [x * 2]));
// [2, 4, 6]
flat() + reduce() 可以使用 reduce() 实现 flat(Infinity):
function flatten(arr) {
return arr.reduce((acc, val) =>
Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []
);
}
console.log(flatten([1, [2, [3, [4, 5]]]]));
// [1, 2, 3, 4, 5]
🔹 flat() 适用于 扁平化嵌套数组 去除数组中的空项 结合 map() 处理数据