在 JavaScript 的编程世界里,数组是一种极为常用且功能强大的数据结构。熟练掌握数组的各种操作方法,对于高效编写代码至关重要。
一、遍历方法
(一)forEach
- 作用:对数组的每个元素执行一次提供的函数,没有返回值。常用于需要对数组元素进行逐个处理,但不关心返回值的场景,比如打印数组元素。
- 特点:会遍历数组中的每一个元素,并且按照顺序依次执行回调函数。
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((number) => {
console.log(number);
});
在这段代码中,forEach方法遍历了numbers数组,并将每个元素传递给回调函数,在控制台打印出每个元素。
(二)map
- 作用:创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。常用于对数组元素进行统一转换,例如将数组中的每个元素乘以 2。
- 特点:返回一个新数组,新数组的长度和原数组相同,且新数组元素是原数组元素经过处理后的结果。
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map((number) => number * 2);
console.log(doubledNumbers); // [2, 4, 6, 8, 10]
这里,map方法将numbers数组中的每个元素乘以 2,并返回一个新数组doubledNumbers。
(三)filter
- 作用:创建一个新数组,新数组中包含原数组中所有通过传入的测试函数的元素。它主要用于筛选出数组中符合特定条件的元素,比如筛选出数组中的偶数。
- 特点:返回一个新数组,新数组中的元素是原数组中满足回调函数条件的元素。回调函数接收三个参数:当前元素的值、当前元素的索引、调用
filter的数组本身,回调函数需要返回一个布尔值,表示当前元素是否满足条件。
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter((number, index, array) => number % 2 === 0);
console.log(evenNumbers); // [2, 4]
上述代码中,filter方法筛选出了numbers数组中的偶数,返回新数组evenNumbers。
(四)reduce
-
作用:对数组中的每个元素执行一个由您提供的
reducer函数(升序执行),将其结果汇总为单个返回值。常用于对数组元素进行累加、累乘等操作,例如计算数组元素的总和。-
reducer函数:这是一个回调函数,它接受四个参数(虽然这里只用到了前两个):accumulator(累加器):在每次迭代中,它存储上一次reducer函数调用的返回值。在第一次调用reducer函数时,它的值是reduce方法的第二个参数(即初始值)。currentValue(当前值):数组中正在处理的当前元素。currentIndex(当前索引,这里未使用):数组中正在处理的当前元素的索引。array(原数组,这里未使用):调用reduce方法的数组。
-
初始值:
reduce方法的第二个参数,这里是 0。它作为accumulator的初始值,也就是第一次调用reducer函数时accumulator的值。
-
-
特点:可以将数组元素进行聚合操作,最终得到一个单一的值。
reducer函数接收四个参数:累加器、当前元素、当前元素的索引、调用reduce的数组本身。第一次调用reducer函数时,累加器的值可以是提供的初始值,如果没有提供初始值,则使用数组的第一个元素作为累加器的初始值,当前元素则从数组的第二个元素开始。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 15
此代码通过reduce方法计算了numbers数组元素的总和。
(五)some
- 作用:测试数组中是否至少有一个元素通过了传入的函数测试,它返回一个布尔值。常用于判断数组中是否存在满足某个条件的元素,比如判断数组中是否有负数。
- 特点:只要数组中有一个元素满足条件,就返回
true,否则返回false。
const numbers = [1, 2, -3, 4, 5];
const hasNegative = numbers.some((number) => number < 0);
console.log(hasNegative); // true
在这段代码中,some方法检查numbers数组中是否存在负数,由于数组中有-3,所以返回true。
(六)every
- 作用:测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值。常用于判断数组中的所有元素是否都满足某个条件,比如判断数组中的元素是否都大于 0。
- 特点:只有当数组中的所有元素都满足条件时,才返回
true,否则返回false。一旦找到不满足条件的元素,every方法就会停止遍历数组。
const numbers = [1, 2, 3, 4, 5];
const allGreaterThanZero = numbers.every((number) => number > 0);
console.log(allGreaterThanZero); // true
上述代码中,every方法检查numbers数组中的所有元素是否都大于 0,由于所有元素都满足条件,所以返回true。
(七)flat
- 作用:按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。常用于将多维数组扁平化,比如将一个包含子数组的数组转换为一个一维数组。
- 特点:不改变原数组,返回一个新数组。其语法为
array.flat([depth]),depth表示要展开的深度,默认为 1。如果depth为Infinity,则可展开任意深度的嵌套数组。
const nestedArray = [1, [2, [3, 4]]];
const flattenedArray = nestedArray.flat(2);
console.log(flattenedArray); // [1, 2, 3, 4]
console.log(nestedArray); // [1, [2, [3, 4]]]
在这段代码中,nestedArray是一个嵌套数组,通过flat(2)方法将其展开到深度为 2 的层级,得到新数组flattenedArray为[1, 2, 3, 4],原数组nestedArray保持不变。当处理需要将多层嵌套数组合并为单一维度数组的场景时,flat方法就非常实用。
(八)flatMap
- 作用:首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它实际上是
map和flat的结合,先对数组中的每个元素应用一个函数进行转换,再将结果数组扁平化。常用于对数组元素进行映射并展开结果,例如将一个包含数组的数组中的每个子数组元素加倍并合并成一个新数组。 - 特点:不改变原数组,返回一个新数组。它的效率比先调用
map再调用flat稍高,因为它可以避免创建一个中间数组。
const arr = [[1, 2], [3, 4]];
const newArr = arr.flatMap(subArr => subArr.map(num => num * 2));
console.log(newArr);
console.log(arr);
在上述代码中,arr是一个包含子数组的数组,通过flatMap方法,先对每个子数组中的元素乘以 2,再将结果扁平化,得到新数组newArr为[2, 4, 6, 8],原数组arr保持不变。当需要对数组进行复杂的数据转换和扁平化操作时,flatMap方法能简洁高效地完成任务。
二、增删元素方法
(一)push
- 作用:在数组的末尾添加一个或多个元素,并返回新的数组长度。常用于向数组末尾添加元素。
- 特点:会改变原数组。
const fruits = ['apple', 'banana'];
const newLength = fruits.push('cherry');
console.log(fruits); // ['apple', 'banana', 'cherry']
console.log(newLength); // 3
这里,push方法向fruits数组末尾添加了cherry,并返回新数组的长度。
(二)pop
- 作用:移除数组的最后一个元素,并返回该元素。常用于移除数组末尾的元素。
- 特点:会直接改变原数组,将数组的最后一个元素删除,并且返回被删除的元素。
const fruits = ['apple', 'banana', 'cherry'];
const removedFruit = fruits.pop();
console.log(fruits); // ['apple', 'banana']
console.log(removedFruit); // cherry
在这段代码中,pop方法移除了fruits数组的最后一个元素cherry,并返回该元素。
(三)shift
- 作用:移除数组的第一个元素,并返回该元素。常用于从数组开头删除元素,比如在处理队列等数据结构时,需要从队头移除元素。
- 特点:会直接改变原数组,将数组的第一个元素删除,并且返回被删除的元素。同时,数组中剩余元素的索引会自动调整。
const fruits = ['apple', 'banana', 'cherry'];
const removedFirstFruit = fruits.shift();
console.log(fruits); // ['banana', 'cherry']
console.log(removedFirstFruit); // apple
此代码中,shift方法移除了fruits数组的第一个元素apple,并返回该元素。
(四)unshift
- 作用:在数组的开头添加一个或多个元素,并返回新的数组长度。常用于向数组开头添加元素。
- 特点:会直接改变原数组,在原数组的开头添加元素,并且返回添加元素后的数组长度。同时,数组中原有元素的索引会自动向后调整。
const fruits = ['banana', 'cherry'];
const newLength = fruits.unshift('apple');
console.log(fruits); // ['apple', 'banana', 'cherry']
console.log(newLength); // 3
这里,unshift方法在fruits数组开头添加了apple,并返回新数组的长度。
(五)splice
- 作用:通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。可以在数组的任意位置进行元素的增删改操作。
- 特点:会改变原数组。
splice方法至少接收两个参数,第一个参数是起始索引,第二个参数是要删除的元素个数。如果提供了更多的参数,则这些参数将作为新元素插入到起始索引位置。
const fruits = ['apple', 'banana', 'cherry'];
const removedElements = fruits.splice(1, 1, 'grape');
console.log(fruits); // ['apple', 'grape', 'cherry']
console.log(removedElements); // ['banana']
上述代码中,splice方法从fruits数组的索引 1 处删除 1 个元素(即banana),并在该位置插入grape,返回被删除的元素banana。
(六)fill
- 作用:用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。如果不指定起始索引和终止索引,将填充整个数组。常用于初始化数组元素为特定值。
- 特点:会改变原数组。
fill方法接收三个参数,第一个参数是用于填充数组的值,第二个参数是起始索引(可选,默认为 0),第三个参数是终止索引(可选,默认为数组的长度)。
const numbers = [1, 2, 3, 4, 5];
numbers.fill(0, 1, 3);
console.log(numbers); // [1, 0, 0, 4, 5]
在上述代码中,fill 方法将 numbers 数组中从索引 1 到索引 3(不包括 3)的元素填充为 0,原数组被修改。
三、合并 / 拆分方法
(一)concat
- 作用:用于合并两个或多个数组。它会创建一个新数组,新数组包含了所有被合并数组的元素。常用于将多个数组合并成一个数组,比如将两个部分的用户数据合并为一个完整的用户列表。
- 特点:不改变原数组,返回一个新数组。可以接收一个或多个数组作为参数,也可以接收单个元素作为参数,这些元素会被添加到新数组中。
const array1 = [1, 2];
const array2 = [3, 4];
const combinedArray = array1.concat(array2, 5);
console.log(combinedArray); // [1, 2, 3, 4, 5]
此代码将array1、array2数组合并,并添加了元素 5,返回新数组combinedArray。
(二)slice
- 作用:返回一个新的数组对象,这个新数组是原数组的一个浅拷贝,拷贝的范围由传入的
begin和end参数决定(包括begin,不包括end)。它常用于截取数组的一部分,比如获取数组的前几个元素、获取数组中间的一段元素等。 - 特点:不改变原数组,返回一个新数组。如果不传入
end参数,则slice方法会截取从begin到数组末尾的所有元素。如果begin是负数,则表示从数组末尾开始计数的索引。
const numbers = [1, 2, 3, 4, 5];
const slicedArray = numbers.slice(1, 3);
console.log(slicedArray); // [ 2, 3 ]
在这段代码中,slice方法从numbers数组中截取了索引 1 到索引 3(不包括 3)的元素,返回新数组slicedArray。
(三)join
- 作用:将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。它常用于将数组元素转换为字符串,比如将一个由单词组成的数组转换为一个句子。
- 特点:返回一个字符串。
join方法可以接收一个可选的分隔符参数,如果不传入分隔符参数,则默认使用逗号作为分隔符。
const words = ['Hello', 'world'];
const sentence = words.join(' ');
console.log(sentence); // Hello world
这里,join方法将words数组的元素用空格连接成一个字符串。
四、查找 / 排序方法
(一)indexOf
- 作用:返回在数组中可以找到一个给定元素的第一个索引,如果不存在该元素,则返回 -1。它常用于查找数组中某个元素的位置,比如在一个学生名单数组中查找某个学生的名字的索引。
- 特点:从数组的开头开始查找,只返回第一个匹配元素的索引。如果数组中存在多个相同的元素,
indexOf方法只会返回第一个出现的元素的索引。
const names = ['Alice', 'Bob', 'Alice', 'Charlie'];
const index = names.indexOf('Alice');
console.log(index); // 0
在这段代码中,indexOf方法找到了Alice在names数组中的第一个索引。
(二)find
- 作用:返回数组中满足提供的测试函数的第一个元素的值。否则返回
undefined。常用于查找数组中满足特定条件的第一个元素,比如在一个商品数组中查找价格低于 100 的第一个商品。 - 特点:返回满足条件的第一个元素的值。回调函数接收三个参数:当前元素的值、当前元素的索引、调用
find的数组本身,回调函数需要返回一个布尔值,表示当前元素是否满足条件。
const products = [
{ name: 'product1', price: 150 },
{ name: 'product2', price: 80 },
{ name: 'product3', price: 200 }
];
const cheapProduct = products.find((product) => product.price < 100);
console.log(cheapProduct); // {name: 'product2', price: 80}
上述代码中,find方法找到了products数组中价格低于 100 的第一个商品。
(三)findIndex
- 作用:返回数组中满足提供的测试函数的第一个元素的索引。如果没有找到满足条件的元素,则返回 -1。它常用于查找数组中满足特定条件的第一个元素的索引,比如在一个任务数组中查找状态为 “未完成” 的第一个任务的索引。
- 特点:返回满足条件的第一个元素的索引。回调函数接收三个参数:当前元素的值、当前元素的索引、调用
findIndex的数组本身,回调函数需要返回一个布尔值,表示当前元素是否满足条件。
const tasks = [
{ id: 1, status: 'completed' },
{ id: 2, status: 'incomplete' },
{ id: 3, status: 'completed' }
];
const incompleteTaskIndex = tasks.findIndex((task) => task.status === 'incomplete');
console.log(incompleteTaskIndex); // 1
这里,findIndex方法找到了tasks数组中状态为 “未完成” 的第一个任务的索引。
(四)sort
- 作用:对数组的元素进行排序,并返回排序后的数组。默认情况下,排序是根据字符串的 Unicode 码点进行的,如果需要按照其他规则排序,比如按照数字大小排序,则需要传入一个比较函数。它常用于对数组元素进行排序,比如对一个学生成绩数组进行升序或降序排列。
- 特点:会改变原数组。比较函数接收两个参数
a和b,如果比较函数返回一个小于 0 的值,则a会排在b前面;如果返回一个大于 0 的值,则b会排在a前面;如果返回 0,则a和b的相对位置不变。
const numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
numbers.sort((a, b) => a - b);
console.log(numbers); //[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
此代码通过传入比较函数,对numbers数组进行了升序排序。
(五)includes
- 作用:
includes方法用于判断一个数组是否包含指定的值,若包含则返回true,反之返回false。常用于在数组中快速检查某个元素是否存在,比如在一个用户权限数组中检查是否包含特定权限。 - 特点:不会改变原数组,返回一个布尔值来表示查找结果。可以指定从数组的某个索引位置开始查找。
const fruits = ['apple', 'banana', 'cherry'];
// 检查数组中是否包含 'banana'
const hasBanana = fruits.includes('banana');
console.log(hasBanana);
// 从索引 2 开始查找 'apple'
const hasAppleFromIndex2 = fruits.includes('apple', 2);
console.log(hasAppleFromIndex2);
此代码示例展示了 includes 方法的基本使用,既可以直接检查元素是否存在于数组中,也能指定起始索引进行查找。