大家好,我是第八哥,一名有 10 年互联网开发经验的老兵。今天跟大伙儿好好聊聊JavaScript数组,这玩意儿在JS里太重要了,不管是新手入门还是老手进阶,都绕不开它。
一、JavaScript数组基础:从创建到访问
先说说数组是啥。简单来说,就是用方括号把一堆数据括起来,数据之间用逗号隔开。比如存几个名字的数组可以这样写:
let names = ['Alice', 'Bob', 'John'];
那么如何访问数组里的元素呢?用索引就行了,记住索引是从0开始的。比如取第一个元素可以这样写:
console.log(names[0]); // 控制台就会输出'Alice'
二、数组增删元素:push、pop、shift、unshift
push:在数组末尾添加一个或多个元素,并返回添加后的数组长度。
比如给names数组加个'Jane':
let len = names.push('Jane');
console.log(names); // 输出 ['Alice', 'Bob', 'John', 'Jane']
console.log(len); // 输出数组的长度 4
或者一次性添加多个元素:
let len = names.push('Charlie', 'Jane');
console.log(names); // ['Alice', 'Bob', 'John', 'Charlie', 'Jane']
console.log(len); // 5
pop:删除数组的最后一个元素,并返回被删除的元素。
let tmp = names.pop(); // 删除数组中的 Jane
console.log(names); // ['Alice', 'Bob', 'John']
console.log(tmp); // Jane
注意:如果对空数组使用pop会返回undefined。
unshift:在数组开头添加一个或多个元素,并返回添加后的数组长度。
let len = names.unshift('Ada');
console.log(names); // 输出 ['Ada', 'Alice', 'Bob', 'John']
console.log(len); // 输出数组的长度 4
或者一次添加多个:
let len = names.push('Ada', 'Mary');
console.log(names); // ['Ada', 'Mary', 'Alice', 'Bob', 'John']
console.log(len); // 5
shift:删除数组的第一个元素,并返回被删除的元素。
let tmp = names.shift(); // 删除数组中的 Ada
console.log(names); // ['Alice', 'Bob', 'John']
console.log(tmp); // Ada
注意:对于空数组,和pop方法一样,都会返回undefined。
在实际开发中,优先推荐使用push/pop
而不是shift/unshift
,因为前者性能更好,时间复杂度为O(1),而后者的时间复杂度为O(n)。对于大型数组要避免频繁的使用shift/unshift,考虑改用其他数据结构。
三、数组遍历:forEach、map、filter
forEach:遍历数组中的每个元素并执行回调函数,无法使用 break
或 return
中断循环。
比如:遍历数组names,打印数组中的每一个元素及对应的索引值。
names.forEach(function (name, index) {
console.log(`索引 ${index} 的值是 ${name}`);
});
// 或者使用箭头函数
names.forEach((name, index) => console.log(`索引 ${index} 的值是 ${name}`));
forEach的回调参数提供(item, index, array)三个参数,方便访问元素信息。
map:遍历数组并返回一个新数组,新数组由回调函数的返回值组成,新数组的长度与原数组相同。
// 给数组中的每个元素前面添加 Hello
let students = names.map(name => 'Hello ' + name);
console.log(students); // ['Hello Alice', 'Hello Bob', 'Hello John']
// 或者转换为对象数组
let objStus = names.map((name, id) => ({
id: id + 1,
name: name
}));
console.log(objStus);
对于大数据量转换考虑Web Worker或分批处理。
filter:根据条件筛选数组元素,返回符合条件的新数组,新数组长度可能小于原数组。
let tmp = names.filter(name => name.includes('o'));
console.log(tmp); // ['Bob', 'John']
复杂的条件可拆分为多个filter调用或提取为独立函数,配合Boolean构造函数可快速过滤假值。
四、数组转换与合并:join、concat、slice
join:将数组中的所有元素连接成一个字符串;不改变原数组;如果是空数组则返回的是空字符串。
let fruits = ['apple', 'banana', 'orange'];
// 默认用逗号连接
console.log(fruits.join()); // "apple,banana,orange"
// 自定义分隔符
console.log(fruits.join('-')); // "apple-banana-orange"
// 空分隔符
console.log(fruits.join('')); // "applebananaorange"
当需要将大型数组转换为字符串时,join()比循环拼接字符串性能更好;数组中的null和undefined会被转换为空字符串。
concat:合并多个数组或值;返回新数组,原数组不变;可以接受数组或非数组参数。
let arr1 = [1, 2];
let arr2 = [3, 4];
// 合并两个数组
let combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4]
// 合并数组和值
let withValues = arr1.concat(5, [6, 7]);
console.log(withValues); // [1, 2, 5, 6, 7]
// 多层数组会展开一层
let nested = arr1.concat([8, [9, 10]]);
console.log(nested); // [1, 2, 8, [9, 10]]
concat只复制数组引用,不深度复制对象元素;在连接大型数组时,考虑使用扩展运算符(...)可能更高效。
slice:截取数组或字符串,返回数组或字符串的浅拷贝部分;不改变原数组或字符串。
let numbers = [0, 1, 2, 3, 4, 5];
// 获取索引1到3(不包括3)的元素
console.log(numbers.slice(1, 3)); // [1, 2]
// 从索引2开始到结束
console.log(numbers.slice(2)); // [2, 3, 4, 5]
// 复制整个数组
console.log(numbers.slice()); // [0, 1, 2, 3, 4, 5]
// 负索引表示从末尾开始
console.log(numbers.slice(-3)); // [3, 4, 5]
slice的第一个参数是起始索引(包含),第二个是结束索引(不包含);支持负数索引,表示从末尾开始计算。
五、数组高级用法:reduce
reduce 通过迭代处理数组元素并将结果累积为单个值,不仅可以用来进行数值计算,还能做复杂处理,比如统计元素出现次数、数据转换、数据分组等,只要灵活运用回调函数就行。
数值计算:
// 数组求和,0为累积器acc的初始值,如果不提供,则首次调用回调时acc的值为数组的第一个元素的值
[1, 2, 3].reduce((acc, cur) => acc + cur, 0); // 6
// 求最大值
[8, 3, 11, 5].reduce((max, num) => Math.max(max, num)); // 11
数据转换:
// 数组转对象
[['name', 'Alice'], ['age', 30]].reduce((obj, [key, val]) => {
obj[key] = val;
return obj;
}, {}); // {name: 'Alice', age: 30}
// 扁平化二维数组
[[1, 2], [3, 4]].reduce((flat, arr) => flat.concat(arr), []); // [1,2,3,4]
数据聚合:
// 统计元素频率
['apple', 'banana', 'apple'].reduce((count, fruit) => {
count[fruit] = (count[fruit] || 0) + 1;
return count;
}, {}); // {apple: 2, banana: 1}
// 分组数据
const people = [
{ name: 'Alice', dept: 'HR' },
{ name: 'Bob', dept: 'IT' },
{ name: 'John', dept: 'IT' },
{ name: 'Jane', dept: 'HR' }
];
people.reduce((groups, person) => {
const dept = person.dept;
groups[dept] = groups[dept] || [];
groups[dept].push(person);
return groups;
}, {});
掌握这些方法,对付日常开发里的数组操作基本没什么问题了。多写多练,很快就能熟练。要是有疑问,欢迎留言交流~
评论