前言
JavaScript 数组是前端开发中最常用的数据结构之一,它灵活强大但也有一些"坑"。本文将全面介绍数组的特性、常用API及注意事项,助你成为数组操作高手!
认识 JavaScript 数组 📚
JavaScript 数组与其他语言不同:
- 🔢 长度不固定:可以动态扩容
- 🎭 类型不固定:一个数组可以包含多种数据类型
- 🏷️ 具有哈希特性:可以像对象一样使用非数字键
const arr = [1, 'two', {name: 'three'}, [4]];
arr['customKey'] = 'value'; // 可行但不推荐
数组初始化方法 🏗️
1. 数组字面量 (推荐)
const arr1 = [1, 2, 3]; // 最常用的方式
2. new Array 构造函数
const arr2 = new Array(5); // 创建长度为5的空数组
⚠️ 注意:new Array(5) 创建的数组是"空槽位"(empty),不是填充了undefined。这会影响遍历:
const arr = new Array(3);
console.log(arr); // [empty × 3]
for (let key in arr) {
console.log(key); // 不会执行,因为空槽位不可枚举
}
3. 使用 fill 填充数组
const arr3 = new Array(5).fill(undefined); // 真正填充了undefined
4. 静态方法 Array.of
console.log(Array.of(1, 2, 3)); // [1, 2, 3]
5. 静态方法 Array.from (强大!)
// 生成字母表
console.log(Array.from(new Array(26), (val, index) => {
return String.fromCodePoint(65 + index);
}));
// ["A", "B", "C", ..., "Z"]
| 特性 | Array.of | Array.from |
|---|---|---|
| 主要目的 | 创建包含参数的新数组 | 转换类数组/可迭代对象为真数组 |
| 参数处理 | 直接使用参数作为数组元素 | 处理第一个参数并可选映射 |
| 参数数量 | 任意数量参数 | 1-3个参数(源, mapFn, thisArg) |
| 特殊行为 | 无,参数总是成为元素 | 可以处理类数组和可迭代对象 |
| 典型用例 | 替代 new Array() 的歧义情况 | 转换 DOM 集合、字符串、生成器等 |
- 当需要直接创建包含特定元素的数组时,使用
Array.of - 当需要转换或映射类数组/可迭代对象时,使用
Array.from Array.from功能更强大,支持映射转换,而Array.of更专注于解决构造函数歧义问题
数组遍历方法 🔍
1. 传统 for 循环
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
✅ 优点:性能最好
❌ 缺点:可读性较差
2. for...in (不推荐用于数组)
for (let key in arr) {
console.log(key, arr[key]);
}
⚠️ 注意:会遍历所有可枚举属性,包括非数字键,原型链上面的数据也会枚举
3. for...of (推荐)
for (let item of arr) {
console.log(item);
}
如果想详细了解for ... in 和 for ... of 之前的区别可以看JavaScript 中的 for...in 和 for...of 循环详解
4. entries() 获取索引和值
for (const [index, value] of arr.entries()) {
console.log(index, value);
}
5. forEach
arr.forEach((item, index) => {
console.log(index, item);
});
⚠️ 注意:无法使用break中断循环,return也只能跳过当前项,如果要遍历所有项可以使用some或every进行检测
数组转换与排序
1. sort - 排序
const unsorted = [3, 1, 4, 2];
// 默认按字符串排序
unsorted.sort(); // [1, 2, 3, 4]
// 自定义排序
unsorted.sort((a, b) => b - a); // [4, 3, 2, 1]
2. reverse - 反转
const arr = [1, 2, 3];
arr.reverse(); // [3, 2, 1]
3. flat/flatMap - 扁平化
const nested = [1, [2, [3, [4]]]];
// 扁平化一层
nested.flat(); // [1, 2, [3, [4]]]
// 扁平化所有层
nested.flat(Infinity); // [1, 2, 3, 4]
// flatMap = map + flat(1)
const phrases = ["hello world", "goodbye moon"];
const words = phrases.flatMap(phrase => phrase.split(' '));
// ["hello", "world", "goodbye", "moon"]
实用数组方法 🛠️
1. reduce - 数组归约
// 求和
console.log([1, 2, 3, 4, 5, 6].reduce((prev, curr) => {
return prev + curr;
}, 0)); // 21
2. map - 数组映射
const doubled = [1, 2, 3].map(x => x * 2); // [2, 4, 6]
3. filter - 数组过滤
const evens = [1, 2, 3, 4].filter(x => x % 2 === 0); // [2, 4]
4. find/findIndex - 查找元素
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
// find - 查找第一个符合条件的元素
const bob = users.find(user => user.name === 'Bob');
// findIndex - 查找第一个符合条件的元素的索引
const bobIndex = users.findIndex(user => user.name === 'Bob');
// includes - 检查是否包含某元素
const hasTwo = numbers.includes(2); // true
// indexOf/lastIndexOf - 查找元素位置
const idx = numbers.indexOf(2); // 1
5. some/every - 条件检测
// some - 是否有元素满足条件
const hasEven = numbers.some(num => num % 2 === 0); // true
// every - 是否所有元素都满足条件
const allEven = numbers.every(num => num % 2 === 0); // false
高级技巧与注意事项 ⚠️
-
稀疏数组问题:
const sparse = new Array(5); sparse[2] = 'value'; console.log(sparse); // [empty × 2, "value", empty × 2]稀疏数组在某些方法中表现可能不符合预期
-
原型方法检查:
const arr = new Array(5); console.log(arr.hasOwnProperty(0)); // false -
性能考虑:对于大型数组,传统for循环通常性能最好
-
避免修改数组长度:直接修改
length可能导致意外行为const arr = [1, 2, 3]; arr.length = 1; // arr现在是[1]
总结 🎯
JavaScript数组功能强大但也有一些"陷阱"。掌握各种初始化方法、遍历方式和实用API,能让你在开发中游刃有余。记住:
- 🏆 优先使用数组字面量
[]创建数组 - 🔄 遍历推荐
for...of或forEach - 🧠 理解稀疏数组和空槽位的区别
- ⚡ 根据场景选择合适的数组方法
希望这篇指南能帮助你更好地理解和运用JavaScript数组!
本文很多都是参考Array,里面有很多的关于数组的原型API