JavaScript 数组学习总结
JavaScript 数组学习总结
JavaScript 数组是一种特殊的对象,用于存储有序的数据集合。它是 JavaScript 中最常用的数据结构之一,提供了丰富的内置方法来处理数据。以下是对 JavaScript 数组的全面总结:
一、数组基础
1. 数组的定义与创建
数组可以通过多种方式创建:
javascript
// 1. 数组字面量(最常用)
const fruits = ["苹果", "香蕉", "橙子"];
const mixed = [1, "字符串", true, null, { name: "对象" }];// 2. 使用 Array 构造函数
const numbers = new Array(1, 2, 3, 4, 5);
const emptyArray = new Array(5); // 创建长度为 5 的空数组// 3. Array.of() 方法(ES6)
const arrayOf = Array.of(1, 2, 3); // [1, 2, 3]
const singleElement = Array.of(5); // [5],区别于 new Array(5)// 4. Array.from() 方法(ES6)- 从类数组或可迭代对象创建数组
const fromString = Array.from("hello"); // ['h', 'e', 'l', 'l', 'o']
const fromSet = Array.from(new Set([1, 2, 2, 3])); // [1, 2, 3]
const fromMap = Array.from(new Map([[1, 'a'], [2, 'b']])); // [[1, 'a'], [2, 'b']]// 使用映射函数
const doubled = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]
2. 数组的基本特性
javascript
// 数组是对象的一种特殊形式
console.log(typeof fruits); // "object"
console.log(Array.isArray(fruits)); // true// 数组长度
console.log(fruits.length); // 3// 访问数组元素
console.log(fruits[0]); // "苹果"
console.log(fruits[fruits.length - 1]); // "橙子"// 修改数组元素
fruits[1] = "葡萄";
console.log(fruits); // ["苹果", "葡萄", "橙子"]// 添加元素
fruits[3] = "西瓜";
console.log(fruits); // ["苹果", "葡萄", "橙子", "西瓜"]// 稀疏数组
const sparse = [];
sparse[10] = 10;
console.log(sparse.length); // 11
console.log(sparse); // [empty × 10, 10]
二、数组方法
1. 修改原数组的方法(破坏性方法)
javascript
// push() - 在数组末尾添加一个或多个元素,并返回新的长度
const length = fruits.push("草莓", "蓝莓");
console.log(fruits); // ["苹果", "葡萄", "橙子", "西瓜", "草莓", "蓝莓"]
console.log(length); // 6// pop() - 移除并返回数组的最后一个元素
const last = fruits.pop();
console.log(fruits); // ["苹果", "葡萄", "橙子", "西瓜", "草莓"]
console.log(last); // "蓝莓"// shift() - 移除并返回数组的第一个元素
const first = fruits.shift();
console.log(fruits); // ["葡萄", "橙子", "西瓜", "草莓"]
console.log(first); // "苹果"// unshift() - 在数组开头添加一个或多个元素,并返回新的长度
const newLength = fruits.unshift("猕猴桃", "菠萝");
console.log(fruits); // ["猕猴桃", "菠萝", "葡萄", "橙子", "西瓜", "草莓"]
console.log(newLength); // 6// splice() - 从数组中添加/删除元素,返回被删除的元素
// splice(start, deleteCount, itemsToAdd)
const removed = fruits.splice(2, 2, "芒果", "荔枝");
console.log(fruits); // ["猕猴桃", "菠萝", "芒果", "荔枝", "西瓜", "草莓"]
console.log(removed); // ["葡萄", "橙子"]// reverse() - 反转数组中元素的顺序
fruits.reverse();
console.log(fruits); // ["草莓", "西瓜", "荔枝", "芒果", "菠萝", "猕猴桃"]// sort() - 对数组元素进行排序(默认按字符串比较)
const numbers = [5, 3, 8, 1, 2];
numbers.sort();
console.log(numbers); // [1, 2, 3, 5, 8]// 自定义排序函数
const people = [{ name: "张三", age: 25 },{ name: "李四", age: 20 },{ name: "王五", age: 30 }
];people.sort((a, b) => a.age - b.age);
console.log(people); // 按年龄升序排列// fill() - 用一个固定值填充数组中从起始索引到终止索引内的全部元素
const filled = [1, 2, 3, 4, 5].fill(0, 2, 4);
console.log(filled); // [1, 2, 0, 0, 5]
2. 返回新数组的方法(非破坏性方法)
javascript
// slice() - 返回数组的一部分浅拷贝
const sliced = fruits.slice(1, 3);
console.log(sliced); // ["西瓜", "荔枝"]
console.log(fruits); // 原数组不变// concat() - 合并多个数组,返回新数组
const moreFruits = ["香蕉", "樱桃"];
const combined = fruits.concat(moreFruits);
console.log(combined); // ["草莓", "西瓜", "荔枝", "芒果", "菠萝", "猕猴桃", "香蕉", "樱桃"]// join() - 将数组元素连接成字符串
const joined = fruits.join(", ");
console.log(joined); // "草莓, 西瓜, 荔枝, 芒果, 菠萝, 猕猴桃"// split() - 字符串方法,将字符串分割成数组
const words = "Hello,World,JavaScript".split(",");
console.log(words); // ["Hello", "World", "JavaScript"]// map() - 创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果
const doubled = [1, 2, 3].map(num => num * 2);
console.log(doubled); // [2, 4, 6]// filter() - 创建一个新数组,包含通过所提供函数实现的测试的所有元素
const evenNumbers = [1, 2, 3, 4, 5].filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4]// reduce() - 对数组中的每个元素执行一个由您提供的reducer函数,将其结果汇总为单个返回值
const sum = [1, 2, 3, 4, 5].reduce((acc, num) => acc + num, 0);
console.log(sum); // 15// 计算数组中每个元素出现的次数
const countOccurrences = ["a", "b", "a", "c", "b", "a"].reduce((acc, item) => {acc[item] = (acc[item] || 0) + 1;return acc;
}, {});
console.log(countOccurrences); // {a: 3, b: 2, c: 1}// flat() - 创建一个新数组,所有子数组元素递归地连接到该数组中
const nested = [1, [2, [3]]];
const flattened = nested.flat(2); // 深度为 2
console.log(flattened); // [1, 2, 3]// flatMap() - 首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
const sentences = ["Hello world", "I love JavaScript"];
const words = sentences.flatMap(sentence => sentence.split(" "));
console.log(words); // ["Hello", "world", "I", "love", "JavaScript"]
3. 查找和判断方法
javascript
// indexOf() - 返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1
const index = fruits.indexOf("芒果");
console.log(index); // 3// lastIndexOf() - 返回指定元素在数组中的最后一个的索引,如果不存在则返回-1
const lastIndex = fruits.lastIndexOf("芒果");
console.log(lastIndex); // 3// includes() - 判断一个数组是否包含一个指定的值
const hasMango = fruits.includes("芒果");
console.log(hasMango); // true// find() - 返回数组中满足提供的测试函数的第一个元素的值
const person = people.find(p => p.age > 20);
console.log(person); // { name: "张三", age: 25 }// findIndex() - 返回数组中满足提供的测试函数的第一个元素的索引
const personIndex = people.findIndex(p => p.age > 20);
console.log(personIndex); // 0// every() - 测试一个数组内的所有元素是否都能通过某个指定函数的测试
const allAdults = people.every(p => p.age >= 18);
console.log(allAdults); // true// some() - 测试数组中是不是至少有1个元素通过了被提供的函数测试
const hasYoungPerson = people.some(p => p.age < 25);
console.log(hasYoungPerson); // true
4. 迭代方法
javascript
// forEach() - 对数组的每个元素执行一次提供的函数
fruits.forEach(fruit => {console.log(fruit);
});// for...of 循环(ES6)
for (const fruit of fruits) {console.log(fruit);
}// for...in 循环(不推荐用于数组)
for (const index in fruits) {console.log(fruits[index]);
}
三、数组排序
1. 默认排序
javascript
// 默认按字符串 Unicode 编码排序
const mixed = [10, 1, 2, "10", "2", "a", "A"];
mixed.sort();
console.log(mixed); // ['10', 1, 10, '2', 2, 'A', 'a']
2. 自定义排序
javascript
// 数字排序
const numbers = [5, 3, 8, 1, 2];
numbers.sort((a, b) => a - b); // 升序
console.log(numbers); // [1, 2, 3, 5, 8]numbers.sort((a, b) => b - a); // 降序
console.log(numbers); // [8, 5, 3, 2, 1]// 字符串排序(不区分大小写)
const words = ["banana", "Apple", "cherry"];
words.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
console.log(words); // ["Apple", "banana", "cherry"]// 对象排序
const products = [{ name: "手机", price: 3000 },{ name: "电脑", price: 5000 },{ name: "平板", price: 2000 }
];// 按价格升序
products.sort((a, b) => a.price - b.price);
console.log(products);
四、数组与字符串的转换
1. 数组转字符串
javascript
const arr = ["a", "b", "c"];// join() 方法
const joined = arr.join(); // "a,b,c"
const customJoined = arr.join("-"); // "a-b-c"// toString() 方法
const str = arr.toString(); // "a,b,c"
2. 字符串转数组
javascript
const str = "Hello,World";// split() 方法
const chars = str.split(""); // ["H", "e", "l", "l", "o", ",", "W", "o", "r", "l", "d"]
const words = str.split(","); // ["Hello", "World"]// ES6 扩展运算符
const chars2 = [...str]; // ["H", "e", "l", "l", "o", ",", "W", "o", "r", "l", "d"]
五、数组的高级应用
1. 多维数组
javascript
// 创建二维数组
const matrix = [[1, 2, 3],[4, 5, 6],[7, 8, 9]
];// 访问多维数组元素
console.log(matrix[1][2]); // 6// 二维数组转一维数组
const flattened = matrix.flat(); // [1, 2, 3, 4, 5, 6, 7, 8, 9]// 遍历多维数组
matrix.forEach(row => {row.forEach(cell => {console.log(cell);});
});
2. 数组去重
javascript
// 使用 Set(ES6)
const duplicates = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(duplicates)];
console.log(unique); // [1, 2, 3]// 使用 filter() 方法
const unique2 = duplicates.filter((value, index, self) => {return self.indexOf(value) === index;
});
console.log(unique2); // [1, 2, 3]
3. 数组扁平化
javascript
// 递归实现
function flatten(arr) {return arr.reduce((acc, val) => {return acc.concat(Array.isArray(val) ? flatten(val) : val);}, []);
}const deeplyNested = [1, [2, [3, [4]]]];
console.log(flatten(deeplyNested)); // [1, 2, 3, 4]// 使用 flat() 方法(ES6)
console.log(deeplyNested.flat(Infinity)); // [1, 2, 3, 4]
4. 数组分组
javascript
// 根据条件分组
const numbers = [1, 2, 3, 4, 5, 6];
const grouped = numbers.reduce((acc, num) => {const key = num % 2 === 0 ? "偶数" : "奇数";if (!acc[key]) {acc[key] = [];}acc[key].push(num);return acc;
}, {});console.log(grouped); // {奇数: [1, 3, 5], 偶数: [2, 4, 6]}
5. 数组的交集、并集和差集
javascript
const arr1 = [1, 2, 3, 4];
const arr2 = [3, 4, 5, 6];// 交集
const intersection = arr1.filter(value => arr2.includes(value));
console.log(intersection); // [3, 4]// 并集
const union = [...new Set([...arr1, ...arr2])];
console.log(union); // [1, 2, 3, 4, 5, 6]// 差集(arr1 中独有的元素)
const difference = arr1.filter(value => !arr2.includes(value));
console.log(difference); // [1, 2]
六、性能考虑
- 访问元素:数组的随机访问性能非常好,时间复杂度为 O (1)
- 添加 / 删除元素:
- 在数组末尾添加 / 删除元素(push/pop):O (1)
- 在数组开头添加 / 删除元素(unshift/shift):O (n),需要移动所有元素
- 在数组中间添加 / 删除元素(splice):O (n)
- 迭代方法:
- for 循环通常比 forEach、map 等方法快
- for...of 循环比 for...in 循环性能更好
- 大数组操作:处理大数组时,注意内存使用和性能问题
- 避免稀疏数组:稀疏数组会降低性能
七、注意事项
- 引用类型:数组是引用类型,赋值和传递时传递的是引用而非副本
- 深拷贝 vs 浅拷贝:
- 浅拷贝:
slice()
、concat()
、扩展运算符(...
) - 深拷贝:可以使用
JSON.parse(JSON.stringify())
(但不能处理函数、RegExp 等)
- 浅拷贝:
- 类数组对象:如 arguments、DOM 节点列表等,可以使用
Array.from()
或扩展运算符转换为数组 - 数组空位:避免在数组中使用空位,会导致意外行为
- 遍历方法的返回值:
- forEach:返回 undefined
- map、filter、reduce 等:返回新数组或值
JavaScript 数组是一种功能强大且灵活的数据结构,掌握数组的各种方法和应用场景对于编写高效的 JavaScript 代码至关重要。合理使用数组方法可以简化代码,提高开发效率。