数组方法

push和pop

pushpop用于操作数组末尾。

push方法

const arr = [1, 2, 3];

// 添加元素到末尾
arr.push(4);  // 返回新长度4
console.log(arr);  // [1, 2, 3, 4]

// 添加多个元素
arr.push(5, 6, 7);  // 返回新长度7
console.log(arr);  // [1, 2, 3, 4, 5, 6, 7]

// 合并数组
const arr2 = [8, 9];
arr.push(...arr2);
console.log(arr);  // [1, 2, 3, 4, 5, 6, 7, 8, 9]

pop方法

const arr = [1, 2, 3];

// 移除末尾元素
const last = arr.pop();  // 返回3
console.log(arr);  // [1, 2]

// 空数组返回undefined
const empty = [];
console.log(empty.pop());  // undefined

应用场景

// 实现栈
const stack = [];
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.pop());  // 3
console.log(stack.pop());  // 2

shift和unshift

shiftunshift用于操作数组开头。

unshift方法

const arr = [3, 4, 5];

// 添加元素到开头
arr.unshift(1, 2);  // 返回新长度5
console.log(arr);  // [1, 2, 3, 4, 5]

shift方法

const arr = [1, 2, 3];

// 移除开头元素
const first = arr.shift();  // 返回1
console.log(arr);  // [2, 3]

性能考虑

// push/pop比shift/unshift快
// 因为shift/unshift需要移动所有元素

// 大量操作时注意性能
const arr = [];
for (let i = 0; i < 100000; i++) {
    arr.push(i);  // 快
}

for (let i = 0; i < 100000; i++) {
    arr.unshift(i);  // 慢
}

slice和splice

slicesplice用于截取和修改数组。

slice方法

const arr = [1, 2, 3, 4, 5];

// slice(start, end):返回新数组,不修改原数组
arr.slice(1, 3);   // [2, 3]
arr.slice(2);      // [3, 4, 5]
arr.slice(-2);     // [4, 5]
arr.slice(1, -1);  // [2, 3, 4]
arr.slice();       // [1, 2, 3, 4, 5](浅拷贝)

console.log(arr);  // [1, 2, 3, 4, 5](原数组不变)

splice方法

const arr = [1, 2, 3, 4, 5];

// splice(start, deleteCount, ...items):修改原数组
// 删除元素
arr.splice(2, 1);  // 返回[3]
console.log(arr);  // [1, 2, 4, 5]

// 插入元素
arr.splice(2, 0, 3);  // 返回[]
console.log(arr);  // [1, 2, 3, 4, 5]

// 替换元素
arr.splice(2, 1, "三");  // 返回[3]
console.log(arr);  // [1, 2, "三", 4, 5]

// 删除多个并插入
arr.splice(1, 2, "二", "三");  // 返回[2, "三"]
console.log(arr);  // [1, "二", "三", 4, 5]

slice vs splice

特性 slice splice 东巴文建议
修改原数组 -
返回值 新数组 删除的元素 -
用途 复制/截取 删除/插入/替换 -

concat

concat用于合并数组。

基本用法

const arr1 = [1, 2];
const arr2 = [3, 4];

// 合并数组
const merged = arr1.concat(arr2);  // [1, 2, 3, 4]
console.log(arr1);  // [1, 2](原数组不变)

// 合并多个数组
const arr3 = [5, 6];
const merged2 = arr1.concat(arr2, arr3);  // [1, 2, 3, 4, 5, 6]

// 合并值
const merged3 = arr1.concat(3, 4, [5, 6]);  // [1, 2, 3, 4, 5, 6]

浅拷贝

const arr = [{ name: "东巴文" }];
const copied = arr.concat();

copied[0].name = "JavaScript";
console.log(arr[0].name);  // "JavaScript"(浅拷贝)

展开运算符替代

const arr1 = [1, 2];
const arr2 = [3, 4];

// concat
const merged1 = arr1.concat(arr2);

// 展开运算符
const merged2 = [...arr1, ...arr2];

join

join将数组转换为字符串。

基本用法

const arr = ["东", "巴", "文"];

arr.join();       // "东,巴,文"(默认逗号)
arr.join("");     // "东巴文"
arr.join("-");    // "东-巴-文"
arr.join(" ");    // "东 巴 文"

应用场景

// URL路径
const path = ["api", "v1", "users"];
const url = "/" + path.join("/");  // "/api/v1/users"

// CSS类名
const classes = ["btn", "btn-primary", "active"];
const className = classes.join(" ");  // "btn btn-primary active"

// CSV格式
const data = [
    ["name", "age", "city"],
    ["东巴文", "1", "北京"],
    ["张三", "20", "上海"]
];
const csv = data.map(row => row.join(",")).join("\n");

与split配合

const str = "东-巴-文";
const arr = str.split("-");  // ["东", "巴", "文"]
const str2 = arr.join("-");  // "东-巴-文"

reverse

reverse反转数组。

基本用法

const arr = [1, 2, 3, 4, 5];

arr.reverse();  // [5, 4, 3, 2, 1]
console.log(arr);  // [5, 4, 3, 2, 1](修改原数组)

不修改原数组的反转

const arr = [1, 2, 3, 4, 5];

// 使用slice先复制
const reversed = arr.slice().reverse();
console.log(arr);       // [1, 2, 3, 4, 5]
console.log(reversed);  // [5, 4, 3, 2, 1]

// 使用展开运算符
const reversed2 = [...arr].reverse();

反转字符串

const str = "东巴文";
const reversed = str.split("").reverse().join("");
console.log(reversed);  // "文巴东"

sort

sort对数组进行排序。

默认排序

// 默认按字符串Unicode码点排序
const arr = [10, 2, 30, 4, 100];
arr.sort();  // [10, 100, 2, 30, 4](字符串排序)

const names = ["东巴文", "JavaScript", "HTML"];
names.sort();  // ["HTML", "JavaScript", "东巴文"]

自定义排序

// 数字升序
const numbers = [10, 2, 30, 4, 100];
numbers.sort((a, b) => a - b);  // [2, 4, 10, 30, 100]

// 数字降序
numbers.sort((a, b) => b - a);  // [100, 30, 10, 4, 2]

// 对象数组排序
const users = [
    { name: "东巴文", age: 1 },
    { name: "张三", age: 20 },
    { name: "李四", age: 15 }
];

users.sort((a, b) => a.age - b.age);
// [{ name: "东巴文", age: 1 }, { name: "李四", age: 15 }, { name: "张三", age: 20 }]

排序规则

// 比较函数返回值
// 负数:a排在b前面
// 正数:b排在a前面
// 0:顺序不变

arr.sort((a, b) => {
    if (a < b) return -1;  // a在前
    if (a > b) return 1;   // b在前
    return 0;              // 相等
});

// 简写
arr.sort((a, b) => a - b);  // 升序
arr.sort((a, b) => b - a);  // 降序

字符串排序

const names = ["东巴文", "abc", "ABC", "123"];

// 区分大小写
names.sort();  // ["123", "ABC", "abc", "东巴文"]

// 不区分大小写
names.sort((a, b) => a.localeCompare(b, "zh-CN"));

// 中文排序
const chinese = ["张三", "李四", "王五"];
chinese.sort((a, b) => a.localeCompare(b, "zh-CN"));

indexOf和lastIndexOf

查找元素在数组中的位置。

indexOf

const arr = [1, 2, 3, 2, 1];

arr.indexOf(2);     // 1(第一个匹配)
arr.indexOf(2, 2);  // 3(从索引2开始查找)
arr.indexOf(4);     // -1(未找到)

lastIndexOf

const arr = [1, 2, 3, 2, 1];

arr.lastIndexOf(2);     // 3(最后一个匹配)
arr.lastIndexOf(2, 2);  // 1(从索引2向前查找)
arr.lastIndexOf(4);     // -1

查找NaN

const arr = [1, NaN, 2];

arr.indexOf(NaN);  // -1(indexOf无法找到NaN)

// 使用includes
arr.includes(NaN);  // true

// 使用findIndex
arr.findIndex(Number.isNaN);  // 1

includes

检查数组是否包含某个元素。

基本用法

const arr = [1, 2, 3, NaN];

arr.includes(2);     // true
arr.includes(4);     // false
arr.includes(NaN);   // true(可以检测NaN)

// 从指定位置开始
arr.includes(1, 1);  // false(从索引1开始)
arr.includes(1, -3); // true(从倒数第3个开始)

includes vs indexOf

const arr = [1, 2, 3, NaN];

// indexOf
arr.indexOf(2) !== -1;  // true
arr.indexOf(NaN) !== -1;  // false(无法检测NaN)

// includes
arr.includes(2);    // true
arr.includes(NaN);  // true

// 东巴文建议:检查存在性用includes

find和findIndex

查找满足条件的元素。

find方法

const users = [
    { id: 1, name: "东巴文" },
    { id: 2, name: "张三" },
    { id: 3, name: "李四" }
];

// 返回第一个满足条件的元素
const found = users.find(user => user.id === 2);
console.log(found);  // { id: 2, name: "张三" }

// 未找到返回undefined
const notFound = users.find(user => user.id === 99);
console.log(notFound);  // undefined

findIndex方法

const users = [
    { id: 1, name: "东巴文" },
    { id: 2, name: "张三" },
    { id: 3, name: "李四" }
];

// 返回第一个满足条件的索引
const index = users.findIndex(user => user.id === 2);
console.log(index);  // 1

// 未找到返回-1
const notFound = users.findIndex(user => user.id === 99);
console.log(notFound);  // -1

findLast和findLastIndex(ES2023)

const arr = [1, 2, 3, 4, 5];

// 从后往前查找
arr.findLast(x => x > 2);       // 5
arr.findLastIndex(x => x > 2);  // 4

every和some

检查数组元素是否满足条件。

every方法

const arr = [2, 4, 6, 8, 10];

// 所有元素都满足条件
arr.every(x => x > 0);   // true
arr.every(x => x > 5);   // false

// 空数组返回true
[].every(x => x > 0);    // true

some方法

const arr = [1, 2, 3, 4, 5];

// 至少一个元素满足条件
arr.some(x => x > 3);    // true
arr.some(x => x > 10);   // false

// 空数组返回false
[].some(x => x > 0);     // false

应用场景

// 验证所有字段
const form = {
    name: "东巴文",
    email: "test@example.com",
    age: 1
};

const isValid = Object.values(form).every(v => v);

// 检查权限
const permissions = ["read", "write"];
const canDelete = permissions.some(p => p === "delete");

filter

过滤数组元素。

基本用法

const numbers = [1, 2, 3, 4, 5, 6];

// 过滤偶数
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens);  // [2, 4, 6]

// 过滤大于3的数
const big = numbers.filter(n => n > 3);
console.log(big);  // [4, 5, 6]

过滤对象数组

const users = [
    { name: "东巴文", age: 1, active: true },
    { name: "张三", age: 20, active: false },
    { name: "李四", age: 15, active: true }
];

// 过滤活跃用户
const activeUsers = users.filter(u => u.active);

// 过滤成年用户
const adults = users.filter(u => u.age >= 18);

去除假值

const arr = [0, 1, false, 2, "", 3, null, undefined, NaN];

// 去除假值
const truthy = arr.filter(Boolean);
console.log(truthy);  // [1, 2, 3]

map

映射数组元素。

基本用法

const numbers = [1, 2, 3, 4, 5];

// 每个元素乘以2
const doubled = numbers.map(n => n * 2);
console.log(doubled);  // [2, 4, 6, 8, 10]

// 每个元素平方
const squared = numbers.map(n => n * n);
console.log(squared);  // [1, 4, 9, 16, 25]

映射对象数组

const users = [
    { id: 1, name: "东巴文" },
    { id: 2, name: "张三" }
];

// 提取属性
const names = users.map(u => u.name);  // ["东巴文", "张三"]

// 转换结构
const formatted = users.map(u => ({
    ...u,
    displayName: `用户: ${u.name}`
}));

链式调用

const numbers = [1, 2, 3, 4, 5, 6];

const result = numbers
    .filter(n => n % 2 === 0)  // [2, 4, 6]
    .map(n => n * 2);          // [4, 8, 12]

console.log(result);  // [4, 8, 12]

reduce

归约数组为单个值。

基本用法

const numbers = [1, 2, 3, 4, 5];

// 求和
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum);  // 15

// 求积
const product = numbers.reduce((acc, cur) => acc * cur, 1);
console.log(product);  // 120

参数说明

arr.reduce((accumulator, currentValue, index, array) => {
    // accumulator: 累加器
    // currentValue: 当前值
    // index: 当前索引
    // array: 原数组
}, initialValue);

常见应用

const numbers = [1, 2, 3, 4, 5];

// 最大值
const max = numbers.reduce((a, b) => a > b ? a : b);

// 最小值
const min = numbers.reduce((a, b) => a < b ? a : b);

// 计数
const words = ["东", "巴", "文", "东", "巴"];
const count = words.reduce((acc, word) => {
    acc[word] = (acc[word] || 0) + 1;
    return acc;
}, {});
// { 东: 2, 巴: 2, 文: 1 }

// 数组扁平化
const nested = [[1, 2], [3, 4], [5]];
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
// [1, 2, 3, 4, 5]

对象数组归约

const users = [
    { name: "东巴文", score: 85 },
    { name: "张三", score: 60 },
    { name: "李四", score: 90 }
];

// 总分
const totalScore = users.reduce((sum, user) => sum + user.score, 0);

// 分组
const grouped = users.reduce((acc, user) => {
    const key = user.score >= 80 ? "pass" : "fail";
    if (!acc[key]) acc[key] = [];
    acc[key].push(user);
    return acc;
}, {});

forEach

遍历数组元素。

基本用法

const arr = ["东", "巴", "文"];

arr.forEach((item, index, array) => {
    console.log(index, item);
});
// 0 "东"
// 1 "巴"
// 2 "文"

与for...of的区别

const arr = [1, 2, 3];

// forEach:无法中断
arr.forEach(x => {
    if (x === 2) return;  // 只是跳过当前迭代
    console.log(x);
});

// for...of:可以中断
for (const x of arr) {
    if (x === 2) break;  // 可以中断
    console.log(x);
}

注意事项

// forEach不返回值
const result = [1, 2, 3].forEach(x => x * 2);
console.log(result);  // undefined

// 不会处理空位
[1, , 3].forEach(x => console.log(x));  // 1, 3

fill

填充数组元素。

基本用法

const arr = [1, 2, 3, 4, 5];

// 全部填充
arr.fill(0);  // [0, 0, 0, 0, 0]

// 指定范围
const arr2 = [1, 2, 3, 4, 5];
arr2.fill(0, 2);      // [1, 2, 0, 0, 0](从索引2开始)
arr2.fill(0, 1, 3);   // [1, 0, 0, 4, 5](索引1到3,不含3)

创建数组

// 创建指定长度的数组并填充
const arr = new Array(5).fill(0);  // [0, 0, 0, 0, 0]

// 注意对象填充是引用
const arr2 = new Array(3).fill({});
arr2[0].name = "东巴文";
console.log(arr2);  // [{ name: "东巴文" }, { name: "东巴文" }, { name: "东巴文" }]

// 使用from避免引用问题
const arr3 = Array.from({ length: 3 }, () => ({}));

copyWithin

在数组内部复制元素。

基本用法

const arr = [1, 2, 3, 4, 5];

// 从索引0复制到索引3
arr.copyWithin(3);  // [1, 2, 3, 1, 2]

const arr2 = [1, 2, 3, 4, 5];
// 从索引0到2复制到索引3
arr2.copyWithin(3, 0, 2);  // [1, 2, 3, 1, 2]

const arr3 = [1, 2, 3, 4, 5];
// 从索引-2复制到索引0
arr3.copyWithin(0, -2);  // [4, 5, 3, 4, 5]

flat和flatMap

扁平化数组。

flat方法

const nested = [1, [2, 3], [4, [5, 6]]];

nested.flat();     // [1, 2, 3, 4, [5, 6]](默认深度1)
nested.flat(2);    // [1, 2, 3, 4, 5, 6]
nested.flat(Infinity);  // 完全扁平化

flatMap方法

const arr = [1, 2, 3];

// map + flat
arr.flatMap(x => [x, x * 2]);
// [1, 2, 2, 4, 3, 6]

// 等价于
arr.map(x => [x, x * 2]).flat();

应用场景

// 分割单词
const sentences = ["Hello World", "东巴文 JavaScript"];
const words = sentences.flatMap(s => s.split(" "));
// ["Hello", "World", "东巴文", "JavaScript"]

// 过滤并映射
const numbers = [1, 2, 3, 4, 5];
const result = numbers.flatMap(x => 
    x % 2 === 0 ? [x * 2] : []
);
// [4, 8]

下一步

掌握了数组方法后,让我们继续学习:

  1. 数组高级应用 - 数组高级技巧
  2. 对象属性 - 深入对象
  3. 对象创建与继承 - 学习继承

东巴文(db-w.cn) - 让编程学习更简单

🔧 东巴文寄语:数组方法是JavaScript中最常用的API,掌握push/pop、slice/splice、map/filter/reduce等方法,能让你高效地处理各种数据操作。在 db-w.cn,我们帮你精通每一个方法!