概述

JavaScript 数组是开发中最常用的数据结构之一,掌握其操作方法对于提高编程效率至关重要。以下是我整理的完整数组操作指南。

一、数组创建与初始化在 JavaScript 中,有多种方式可以创建和初始化数组。不同的方法适用于不同的场景,理解它们的区别有助于写出更清晰、更安全的代码。

代码语言:javascript复制// 1. 字面量创建

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

const arr2 = ['a', 'b', 'c'];

// 2. 构造函数创建

const arr3 = new Array(5); // 创建长度为5的空数组

const arr4 = new Array(1, 2, 3); // 创建包含元素的数组

// 3. Array.of() - 解决构造函数歧义

Array.of(7); // [7]

Array.of(1, 2, 3); // [1, 2, 3]

// 4. Array.from() - 从类数组或可迭代对象创建

Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']

Array.from({ length: 5 }); // [undefined, undefined, ...]

Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]

// 5. 填充数组

const filled1 = new Array(5).fill(0); // [0, 0, 0, 0, 0]

const filled2 = Array.from({ length: 5 }, () => 1); // [1, 1, 1, 1, 1] 说明:

使用字面量 [] 是最常见且推荐的方式,简洁直观。new Array(n) 当传入单个数字时会创建稀疏数组(holes),行为容易出错,应避免。Array.of() 能安全地创建指定元素的数组,解决了 new Array() 的歧义问题。Array.from() 不仅能将类数组(如 arguments、NodeList)转为真实数组,还能结合 length 和映射函数生成序列或初始化数组。fill() 和 Array.from() 配合使用,是初始化固定值数组的常用手段。二、元素增删操作数组的增删操作分为在头部、尾部或任意位置进行。不同方法对性能和原数组的影响不同,需根据场景选择合适的方法。

1. 尾部操作尾部操作是最高效的数组修改方式,因为不会影响其他元素的索引。

代码语言:javascript复制const arr = [1, 2, 3];

// push - 尾部添加元素

arr.push(4); // 返回新长度: 4, arr: [1, 2, 3, 4]

arr.push(5, 6); // 可添加多个: [1, 2, 3, 4, 5, 6]

// pop - 尾部删除元素

const last = arr.pop(); // last = 6, arr: [1, 2, 3, 4, 5] 说明:

push() 可接收多个参数,一次性添加多个元素,返回新长度。pop() 删除并返回最后一个元素,数组为空时返回 undefined。这两个方法直接修改原数组,适用于需要累积数据的场景(如栈结构)。2. 头部操作头部操作效率较低,因为每次添加或删除都会导致所有后续元素索引前移或后移。

代码语言:javascript复制// unshift - 头部添加元素

arr.unshift(0); // 返回新长度: 6, arr: [0, 1, 2, 3, 4, 5]

arr.unshift(-2, -1); // [-2, -1, 0, 1, 2, 3, 4, 5]

// shift - 头部删除元素

const first = arr.shift(); // first = -2, arr: [-1, 0, 1, 2, 3, 4, 5] 说明:

unshift() 在数组开头插入一个或多个元素,返回新长度。shift() 删除并返回第一个元素,数组为空返回 undefined。由于性能开销较大,应避免在大型数组中频繁使用。3. 任意位置操作splice() 是最灵活的数组修改方法,可以在任意位置添加、删除或替换元素。

代码语言:javascript复制const arr = [1, 2, 3, 4, 5];

// splice - 多功能修改

// 删除:从索引2开始删除1个元素

arr.splice(2, 1); // 返回删除元素: [3], arr: [1, 2, 4, 5]

// 添加:从索引1开始删除0个元素,添加新元素

arr.splice(1, 0, 'a', 'b'); // arr: [1, 'a', 'b', 2, 4, 5]

// 替换:从索引3开始删除2个元素,添加新元素

arr.splice(3, 2, 'c', 'd'); // 返回删除元素: [2, 4], arr: [1, 'a', 'b', 'c', 'd'] 说明:

splice(start, deleteCount, item1, item2, ...) 从 start 开始删除 deleteCount 个元素,并插入新元素。返回被删除的元素组成的数组。该方法直接修改原数组,适合精确控制数组结构的场景。4. 清空数组清空数组有多种方式,但行为和性能略有差异。

代码语言:javascript复制let arr = [1, 2, 3];

// 方法1: 重新赋值 (推荐)

arr = [];

// 方法2: 修改length属性

arr.length = 0;

// 方法3: splice

arr.splice(0, arr.length); 说明:

重新赋值 arr = [] 最简洁,但如果其他变量引用原数组,则原数组仍存在。arr.length = 0 会清空所有引用该数组的变量,是彻底清空的可靠方式。splice(0) 同样能清空并保留引用,但语法稍显复杂。推荐使用 length = 0 或重新赋值,视引用情况而定。三、数组遍历方法遍历数组是日常开发中最常见的操作。不同遍历方式在语法、性能和用途上各有优劣。

代码语言:javascript复制const numbers = [1, 2, 3, 4, 5];

// 1. for循环 (最基础)

for (let i = 0; i < numbers.length; i++) {

console.log(numbers[i]);

}

// 2. for...of循环 (推荐)

for (const num of numbers) {

console.log(num);

}

// 3. forEach方法

numbers.forEach((num, index, array) => {

console.log(`索引 ${index}: 值 ${num}`);

});

// 4. for...in (不推荐用于数组,会遍历所有可枚举属性)

for (const index in numbers) {

console.log(numbers[index]);

}

// 5. entries() 获取索引和值

for (const [index, value] of numbers.entries()) {

console.log(index, value);

} 说明:

for 循环性能最好,支持 break、continue,适合复杂逻辑。for...of 语法简洁,支持 break 和 yield,推荐用于简单遍历。forEach() 语义清晰,但无法中途跳出(return 仅结束当前回调)。for...in 用于对象,不推荐用于数组,可能遍历到非数字索引或原型属性。entries() 结合 for...of 可同时获取索引和值,是现代 JS 的优雅写法。四、查找与筛选查找和筛选是处理数组数据的核心能力,尤其在处理用户列表、表单验证等场景中非常关键。

1. 查找元素代码语言:javascript复制const users = [

{ id: 1, name: 'Alice', age: 25 },

{ id: 2, name: 'Bob', age: 30 },

{ id: 3, name: 'Charlie', age: 25 }

];

// find - 查找第一个符合条件的元素

const user = users.find(u => u.age === 25); // { id: 1, name: 'Alice', age: 25 }

// findIndex - 查找第一个符合条件的元素索引

const index = users.findIndex(u => u.name === 'Bob'); // 1

// findLast / findLastIndex (ES2023)

const last25 = users.findLast(u => u.age === 25); // { id: 3, name: 'Charlie', age: 25 }

// includes - 检查是否包含某元素

[1, 2, 3].includes(2); // true

// indexOf / lastIndexOf - 查找元素位置

['a', 'b', 'c', 'b'].indexOf('b'); // 1

['a', 'b', 'c', 'b'].lastIndexOf('b'); // 3 说明:

find() 返回第一个匹配元素,未找到返回 undefined。findIndex() 返回索引,未找到返回 -1,适合需要索引的场景。findLast 和 findLastIndex 是 ES2023 新增,从末尾开始查找。includes() 用于基本类型比较,使用 === 判断。indexOf() 对于对象数组不适用(引用不同),应配合 find 使用。2. 筛选数组代码语言:javascript复制const numbers = [1, 2, 3, 4, 5, 6];

// filter - 筛选符合条件的元素

const even = numbers.filter(n => n % 2 === 0); // [2, 4, 6]

const adults = users.filter(u => u.age >= 18);

// 链式调用

const result = users

.filter(u => u.age > 20)

.map(u => u.name); // ['Bob', 'Charlie'] 说明:

filter() 返回一个新数组,包含所有满足条件的元素,不修改原数组。与 find() 不同,filter() 返回数组,即使只有一个匹配项。支持链式调用,常与 map()、sort() 等组合使用,实现函数式编程风格。五、数组转换数组转换是函数式编程的核心,通过映射、扁平化和归约,可以将数据结构灵活变换。

1. 映射转换代码语言:javascript复制const numbers = [1, 2, 3];

// map - 将数组映射为新数组

const doubled = numbers.map(n => n * 2); // [2, 4, 6]

const userNames = users.map(u => u.name); // ['Alice', 'Bob', 'Charlie']

// flatMap - 映射后扁平化 (ES2019)

const phrases = ['hello world', 'good morning'];

const words = phrases.flatMap(phrase => phrase.split(' '));

// ['hello', 'world', 'good', 'morning'] 说明:

map() 是最常用的转换方法,将每个元素通过函数映射为新值。返回新数组,长度与原数组相同。flatMap() 先 map 再 flat(1),适合将一个元素映射为多个并展平,避免嵌套。2. 扁平化数组代码语言:javascript复制const nested = [1, [2, [3, [4]]]];

// flat - 扁平化数组 (ES2019)

nested.flat(); // [1, 2, [3, [4]]]

nested.flat(2); // [1, 2, 3, [4]]

nested.flat(Infinity); // [1, 2, 3, 4]

// 替代方案 (ES6)

const flatten = arr => arr.reduce((acc, val) =>

acc.concat(Array.isArray(val) ? flatten(val) : val), []); 说明:

flat(depth) 将嵌套数组按指定深度展平。Infinity 可完全展平任意深度嵌套。旧版可用 reduce + concat + 递归 实现,但性能较差。3. 归约操作代码语言:javascript复制const numbers = [1, 2, 3, 4, 5];

// reduce - 从左到右归约

const sum = numbers.reduce((acc, curr) => acc + curr, 0); // 15

const max = numbers.reduce((acc, curr) => Math.max(acc, curr), -Infinity); // 5

// reduceRight - 从右到左归约

const reversed = numbers.reduceRight((acc, curr) => [...acc, curr], []); // [5, 4, 3, 2, 1]

// 复杂示例:统计字符出现次数

const chars = ['a', 'b', 'a', 'c', 'b', 'a'];

const count = chars.reduce((acc, char) => {

acc[char] = (acc[char] || 0) + 1;

return acc;

}, {}); // { a: 3, b: 2, c: 1 } 说明:

reduce() 是函数式编程的“瑞士军刀”,可用于求和、拼接、分组、状态累积等。接收累加器 acc 和当前值 curr,初始值通过第二个参数指定。reduceRight() 从右向左处理,适用于需要逆序操作的场景。六、排序与反转排序和反转是改变数组顺序的常用操作,但需注意它们会修改原数组。

代码语言:javascript复制const numbers = [3, 1, 4, 1, 5, 9];

const names = ['John', 'Alice', 'Bob'];

// sort - 排序 (会修改原数组)

numbers.sort(); // [1, 1, 3, 4, 5, 9] - 默认按字符串排序

numbers.sort((a, b) => a - b); // 数字升序

numbers.sort((a, b) => b - a); // 数字降序

names.sort(); // ['Alice', 'Bob', 'John'] - 字符串排序

// 对象数组排序

users.sort((a, b) => a.age - b.age); // 按年龄升序

users.sort((a, b) => a.name.localeCompare(b.name)); // 按姓名排序

// reverse - 反转数组

numbers.reverse(); // [9, 5, 4, 3, 1, 1]

// 创建排序副本 (不修改原数组)

const sorted = [...numbers].sort();

const sorted2 = numbers.slice().sort(); // 等效 说明:

sort() 默认将元素转为字符串比较,数字排序必须提供比较函数 (a, b) => a - b。localeCompare() 用于安全的字符串排序,支持多语言。reverse() 直接反转原数组。如需保留原数组,应使用扩展运算符或 slice() 创建副本后再排序。七、数组切片与连接切片和连接用于提取子数组或合并多个数组,是构建新数组的重要手段。

代码语言:javascript复制const arr = [1, 2, 3, 4, 5];

// slice - 切片 (不修改原数组)

arr.slice(1, 3); // [2, 3] - 索引1到3(不含)

arr.slice(2); // [3, 4, 5] - 从索引2到最后

arr.slice(-2); // [4, 5] - 最后两个元素

arr.slice(1, -1); // [2, 3, 4] - 从1到倒数第1个

// concat - 连接数组

const arr1 = [1, 2];

const arr2 = [3, 4];

const combined = arr1.concat(arr2); // [1, 2, 3, 4]

const combined2 = [...arr1, ...arr2]; // ES6扩展运算符 (推荐)

// join - 数组转字符串

['Hello', 'World'].join(' '); // "Hello World"

[1, 2, 3].join('-'); // "1-2-3" 说明:

slice(start, end) 提取从 start 到 end(不含)的子数组,支持负索引。concat() 可连接多个数组或值,返回新数组。扩展运算符 ... 语法更简洁,是现代 JS 的首选方式。join(separator) 将数组元素拼接为字符串,常用于生成路径、标签等。八、高阶函数应用高阶函数让数组操作更具表达力,支持函数式编程范式,提升代码可维护性。

1. 条件判断代码语言:javascript复制const numbers = [1, 2, 3, 4, 5];

// every - 所有元素都满足条件

numbers.every(n => n > 0); // true

// some - 至少一个元素满足条件

numbers.some(n => n > 4); // true

// 实用示例

const formFields = [{ value: 'abc' }, { value: '' }, { value: 'def' }];

const allFilled = formFields.every(field => field.value.trim() !== ''); // false

const anyFilled = formFields.some(field => field.value.trim() !== ''); // true 说明:

every() 类似逻辑与(AND),全部为真才返回 true。some() 类似逻辑或(OR),任一为真即返回 true。常用于表单验证、权限检查、状态判断等场景。2. 函数式编程模式代码语言:javascript复制// 管道操作模拟

const pipe = (...fns) => (initialValue) =>

fns.reduce((acc, fn) => fn(acc), initialValue);

// 组合函数

const processNumbers = pipe(

arr => arr.filter(n => n % 2 === 0), // 筛选偶数

arr => arr.map(n => n * 2), // 乘以2

arr => arr.reduce((a, b) => a + b, 0) // 求和

);

processNumbers([1, 2, 3, 4, 5]); // 12 (2*2 + 4*2 = 4 + 8) 说明:

函数式编程强调无副作用、数据不可变和函数组合。pipe() 实现了函数的链式调用,每个函数接收上一个的输出。适合处理数据流、构建 DSL 或复杂转换逻辑。九、ES6+ 新特性ES6 及后续版本为数组操作带来了革命性改进,尤其是扩展运算符和解构赋值,极大提升了开发体验。

1. 扩展运算符代码语言:javascript复制// 数组复制

const original = [1, 2, 3];

const copy = [...original];

// 数组合并

const arr1 = [1, 2];

const arr2 = [3, 4];

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

// 函数参数

const numbers = [1, 2, 3];

Math.max(...numbers); // 3

// 添加元素

const newArr = [0, ...numbers, 4]; // [0, 1, 2, 3, 4] 说明:

扩展运算符 ... 可展开可迭代对象,语法简洁,功能强大。广泛用于浅拷贝、合并、函数传参、插入元素等场景。注意:仅支持浅拷贝,嵌套对象仍为引用。2. 解构赋值代码语言:javascript复制const arr = [1, 2, 3, 4, 5];

// 基本解构

const [first, second] = arr; // first = 1, second = 2

// 跳过元素

const [a, , c] = arr; // a = 1, c = 3

// 剩余元素

const [x, y, ...rest] = arr; // x = 1, y = 2, rest = [3, 4, 5]

// 默认值

const [p = 10, q = 20] = [1]; // p = 1, q = 20

// 交换变量

let m = 1, n = 2;

[m, n] = [n, m]; // m = 2, n = 1 说明:

解构赋值让从数组中提取值变得极其简洁。支持跳过、剩余、默认值等高级语法。常用于函数返回值、参数解构、变量交换等场景。3. 新增静态方法代码语言:javascript复制// Array.isArray() - 类型检查

Array.isArray([1, 2, 3]); // true

Array.isArray({}); // false

// Array.from() 的高级用法

const unique = Array.from(new Set([1, 2, 2, 3])); // 去重: [1, 2, 3]

// 创建范围数组

const range = (start, end) =>

Array.from({ length: end - start + 1 }, (_, i) => start + i);

range(1, 5); // [1, 2, 3, 4, 5] 说明:

Array.isArray() 是判断数组的唯一可靠方式(typeof 无效)。Array.from() 结合 Set 可实现去重,结合 length 可生成序列。range() 函数是生成数字序列的常用工具。十、性能优化建议合理选择数组方法不仅能提升代码可读性,还能显著改善性能,尤其是在处理大数据集时。

1. 方法选择指南代码语言:javascript复制// 1. 遍历时不需要返回新数组:forEach > map

// 正确

numbers.forEach(n => console.log(n));

// 2. 需要返回新数组:map > forEach + push

// 推荐

const doubled = numbers.map(n => n * 2);

// 不推荐

const doubled2 = [];

numbers.forEach(n => doubled2.push(n * 2));

// 3. 查找元素:find > filter[0]

// 推荐

users.find(u => u.id === 1);

// 不推荐

users.filter(u => u.id === 1)[0];

// 4. 检查存在性:some > find + Boolean

// 推荐

users.some(u => u.age > 30);

// 不推荐

Boolean(users.find(u => u.age > 30)); 说明:

map() 会创建新数组,若不需要应使用 forEach()。filter()[0] 会遍历整个数组,而 find() 找到即停,性能更优。some() 语义更明确且短路求值,优于 find 后转布尔。2. 避免常见陷阱代码语言:javascript复制// 1. 稀疏数组

const sparse = new Array(5); // [empty × 5]

sparse.map(() => 1); // 仍然 [empty × 5]

// 解决方案

const dense = Array.from({ length: 5 }, () => 1); // [1, 1, 1, 1, 1]

// 2. 修改原数组的方法

const arr = [1, 2, 3];

const sorted = arr.sort(); // arr也被修改了!

// 解决方案

const sortedSafe = [...arr].sort(); // 或 arr.slice().sort()

// 3. 浮点数精度

[0.1, 0.2].reduce((a, b) => a + b); // 0.30000000000000004

// 解决方案

[0.1, 0.2].reduce((a, b) => a + b).toFixed(1); // "0.3" 说明:

稀疏数组的 map、filter 等方法会跳过空位,导致意外行为。sort()、reverse()、splice() 等方法会修改原数组,需注意副作用。浮点数计算应使用 toFixed() 或 Math.round() 处理精度问题。3. 实用工具函数代码语言:javascript复制// 数组去重

const unique = arr => [...new Set(arr)];

unique([1, 2, 2, 3, 1]); // [1, 2, 3]

// 数组分组

const groupBy = (arr, key) =>

arr.reduce((groups, item) => {

const group = groups[item[key]] || [];

return { ...groups, [item[key]]: [...group, item] };

}, {});

// 数组分块

const chunk = (arr, size) =>

Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>

arr.slice(i * size, i * size + size)

);

// 数组随机排序

const shuffle = arr =>

[...arr].sort(() => Math.random() - 0.5); 说明:

Set 去重简洁高效,适用于基本类型。groupBy() 利用 reduce 实现对象分组,常用于数据聚合。chunk() 将数组分页或分批处理。shuffle() 实现洗牌,但 sort() 方式不够随机,生产环境建议用 Fisher-Yates 算法。 总结

这份总结涵盖了 JavaScript 数组的核心操作方法,从基础到高级,从传统到现代。掌握这些方法将极大提升你的开发效率和代码质量。建议在实际项目中多加练习,形成自己的使用习惯和最佳实践。

Copyright © 2088 世界杯决赛_世界杯是 - rchzwh.com All Rights Reserved.
友情链接
top