JavaScript 数据类型补充:数组详解
一、数组的基本概念
数组(Array)是 JavaScript 中用于存储有序数据集合的对象。虽然使用 typeof 检测数组会返回 "object",但数组是 JavaScript 中非常重要且特殊的数据结构。
二、创建数组的方式
1. 字面量表示法(最常用)
let fruits = ["苹果", "香蕉", "橙子"];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, null, {name: "张三"}];
let empty = [];
2. Array 构造函数
let arr1 = new Array(); // 空数组 []
let arr2 = new Array(3); // 长度为3的空数组 [empty × 3]
let arr3 = new Array(1, 2, 3); // [1, 2, 3]
3. ES6+ 新增方式
// Array.of() - 创建包含所有参数的数组
let arr4 = Array.of(7); // [7](与new Array(7)不同)
let arr5 = Array.of(1, 2, 3); // [1, 2, 3]
// Array.from() - 从类数组或可迭代对象创建数组
let arr6 = Array.from("hello"); // ["h", "e", "l", "l", "o"]
let arr7 = Array.from({length: 5}, (v, i) => i); // [0, 1, 2, 3, 4]
三、数组的基本操作
1. 访问元素
let colors = ["red", "green", "blue"];
console.log(colors[0]); // "red"(索引从0开始)
console.log(colors[2]); // "blue"
console.log(colors.length); // 3(数组长度)
2. 修改元素
colors[1] = "yellow"; // ["red", "yellow", "blue"]
colors[3] = "purple"; // ["red", "yellow", "blue", "purple"]
3. 检测数组
let arr = [];
typeof arr; // "object"(不够准确)
Array.isArray(arr); // true(推荐方法)
arr instanceof Array; // true
四、数组的常用方法
1. 添加/删除元素
let arr = [1, 2, 3];
// 末尾添加/删除
arr.push(4); // [1, 2, 3, 4](返回新长度)
arr.pop(); // [1, 2, 3](返回删除的元素)
// 开头添加/删除
arr.unshift(0); // [0, 1, 2, 3](返回新长度)
arr.shift(); // [1, 2, 3](返回删除的元素)
// 任意位置添加/删除
arr.splice(1, 1); // 从索引1删除1个元素
arr.splice(1, 0, "new"); // 从索引1添加元素(不删除)
arr.splice(1, 1, "替换"); // 从索引1替换1个元素
2. 遍历数组
let numbers = [10, 20, 30];
// forEach
numbers.forEach(function(item, index) {
console.log(index, item);
});
// ES6 for...of
for (let num of numbers) {
console.log(num);
}
// 传统 for 循环
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
3. 转换方法
let arr = [1, 2, 3];
// 转为字符串
arr.toString(); // "1,2,3"
arr.join("-"); // "1-2-3"
// 连接数组
let arr2 = [4, 5];
arr.concat(arr2); // [1, 2, 3, 4, 5]
// 复制部分元素
arr.slice(1, 3); // [2, 3](不改变原数组)
4. 查找方法
let fruits = ["apple", "banana", "orange", "banana"];
fruits.indexOf("banana"); // 1(首次出现位置)
fruits.lastIndexOf("banana"); // 3(最后出现位置)
fruits.includes("orange"); // true(是否包含)
// ES6 find/findIndex
[5, 12, 8, 130, 44].find(x => x > 10); // 12(第一个匹配元素)
[5, 12, 8, 130, 44].findIndex(x => x > 10); // 1(第一个匹配索引)
5. 排序与反转
let nums = [3, 1, 4, 1, 5, 9];
nums.sort(); // [1, 1, 3, 4, 5, 9](默认按字符串排序)
nums.sort((a, b) => a - b); // 数字升序排序
nums.sort((a, b) => b - a); // 数字降序排序
nums.reverse(); // 反转数组顺序
6. 迭代与转换(ES5+)
let arr = [1, 2, 3, 4, 5];
// map - 映射新数组
let doubled = arr.map(x => x * 2); // [2, 4, 6, 8, 10]
// filter - 过滤元素
let evens = arr.filter(x => x % 2 === 0); // [2, 4]
// reduce - 累积计算
let sum = arr.reduce((total, num) => total + num, 0); // 15
// every/some - 条件检测
let allPositive = arr.every(x => x > 0); // true
let hasThree = arr.some(x => x === 3); // true
五、多维数组
// 创建二维数组(矩阵)
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
// 访问元素
console.log(matrix[0][1]); // 2(第一行第二列)
// 遍历二维数组
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(matrix[i][j]);
}
}
六、ES6+ 数组新特性
1. 扩展运算符(Spread)
// 复制数组(浅拷贝)
let original = [1, 2, 3];
let copy = [...original];
// 合并数组
let arr1 = [1, 2];
let arr2 = [3, 4];
let merged = [...arr1, ...arr2]; // [1, 2, 3, 4]
// 函数参数
let nums = [1, 2, 3];
Math.max(...nums); // 3
2. 解构赋值
let colors = ["red", "green", "blue"];
let [firstColor, secondColor] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
// 交换变量值
let a = 1, b = 2;
[a, b] = [b, a];
3. Array.prototype.flat()
// 扁平化数组
let nested = [1, [2, [3, [4]]]];
nested.flat(); // [1, 2, [3, [4]]]
nested.flat(2); // [1, 2, 3, [4]]
nested.flat(Infinity); // [1, 2, 3, 4]
4. Array.prototype.flatMap()
// 先映射后扁平化
let arr = [1, 2, 3];
arr.flatMap(x => [x, x * 2]); // [1, 2, 2, 4, 3, 6]
七、数组与对象的关系
数组也是对象
let arr = ["a", "b", "c"];
// 可以像对象一样添加属性(但不推荐)
arr.customProperty = "hello";
console.log(arr.customProperty); // "hello"
// 数组索引实际上是字符串键
console.log(arr[0] === arr["0"]); // true
数组与类数组对象
// 类数组对象(有length属性)
let arrayLike = {
0: "a",
1: "b",
2: "c",
length: 3
};
// 转换为数组
let realArray = Array.from(arrayLike); // ["a", "b", "c"]
// 函数arguments对象
function example() {
let args = Array.from(arguments);
console.log(args);
}
example(1, 2, 3); // [1, 2, 3]
八、性能注意事项
-
访问速度:数组索引访问比对象属性访问更快
-
push/pop vs unshift/shift:末尾操作比开头操作更快
-
循环优化:
// 缓存长度(推荐) for (let i = 0, len = arr.length; i < len; i++) { // 操作 } // 反向循环(有时更快) for (let i = arr.length - 1; i >= 0; i--) { // 操作 } -
避免稀疏数组(有空位的数组)
-
类型化数组(TypedArray):处理二进制数据时更高效
九、实用技巧
1. 数组去重
let arr = [1, 2, 2, 3, 3, 3];
// ES6 Set方法(最简洁)
let unique = [...new Set(arr)]; // [1, 2, 3]
// filter方法
let unique2 = arr.filter((item, index) => arr.indexOf(item) === index);
2. 清空数组
let arr = [1, 2, 3];
arr.length = 0; // 推荐方法(最快且安全)
// arr = []; // 重新赋值(如果数组被其他地方引用,原数组不会改变)
3. 获取随机元素
let colors = ["red", "green", "blue", "yellow"];
function getRandomItem(array) {
return array[Math.floor(Math.random() * array.length)];
}
getRandomItem(colors); // 随机返回一个颜色
4. 数组分块
function chunkArray(arr, size) {
const chunks = [];
for (let i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
chunkArray([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
十、总结要点
- 数组是特殊的对象,具有数字索引和length属性
- 常用方法分类:
- 修改原数组:push/pop、shift/unshift、splice、sort、reverse
- 返回新数组:map、filter、slice、concat
- 遍历:forEach、map、filter、reduce
- 查找:indexOf、find、includes
- ES6+ 特性:扩展运算符、解构、箭头函数、Set/Map
- 性能考虑:选择合适的数据结构和算法
- 最佳实践:优先使用数组方法而非传统循环,保持代码简洁
注意:数组操作时要注意浅拷贝与深拷贝的区别。对于包含对象的数组,许多方法(如slice、扩展运算符)只进行浅拷贝。







