JavaScript 中的高阶数组方法
介绍
高阶函数是指对其他函数进行操作的函数,它可以接收其他函数作为参数,也可以返回其他函数作为输出。它接受一个函数作为参数,或者返回一个函数作为输出。
在本文中,我将向您展示处理数组时最常用的几种方法。
Array.prototype.map
这是你在处理数组时会用到的最简单的函数之一。它会对数组中的每个元素map调用传入的函数,从而创建一个新数组。它会获取回调函数的每个返回值并创建一个新数组。
传递给该函数的回调函数map()可以接受以下三个参数中的任何一个:item,,index。array
例 1
给定一个整数数组,创建一个新数组,其中存储第一个数组中每个整数的两倍,并将结果记录到控制台。
解决方案:
const givenArray = [477, 8914, 40461, 599148];
const newArray = givenArray.map(n => n * 2);
console.log(newArray); // console: [954, 17828, 80922, 1198296]
例 2
给定一个单数名词数组,创建一个新数组,存储第一个数组中每个单词的复数名词,并将其记录到控制台(假设单数名词可以通过添加“s”变成复数)。
解决方案:
const givenArray = [ 'pen', 'book', 'code' ];
const newArray = givenArray.map(w => w + 's');
console.log(newArray); // console: ['pens', 'books', 'codes']
Array.prototype.filter
filter()例如,如果您要根据给定的项目列表创建搜索栏,就可以使用此函数。该方法还会创建一个新数组,方法是对数组中的每个元素filter()执行传入的回调函数,并且仅当元素通过回调函数返回的布尔测试时,才将其保留在结果数组中。
传递给该filter()方法的回调函数接受以下三个参数中的任意一个:item,index和array;与该方法相同map()。
例 1
给定一个包含不同产品成本的数组,如果成本小于等于 350 美元,则创建一个新数组,其中包含输入数组中的成本,并将其打印到控制台。
解决方案:
const givenArray = [390, 190, 311.85, 67, 19048, 5000, 670];
const newArray = givenArray.filter(c => c <= 350);
console.log(newArray) // console: [190, 311.85, 67];
例 2
给定一个包含城市名称和人口的对象数组,如果该城市的人口大于等于 500 万,则创建一个包含第一个数组中对象的数组。
解决方案:
const givenArray = [
{ "name": "Shanghai", "population": 24300000 },
{ "name": "Los Angeles", "population": 3792621 },
{ "name": "New Delhi", "population": 21800000 },
{ "name": "Mumbai", "population": 18400000 },
{ "name": "Chicago", "population": 2695598 },
{ "name": "Houston", "population": 2100263 },
];
const newArray = givenArray.filter( ({ population }) => population >= 5000000);
console.log(newArray); // console: [{name: "Shanghai", population: 24300000}, {name: "New Delhi", population: 21800000}, {name: "Mumbai", population: 18400000}]
Array.prototype.reduce
该reduce()方法创建一个新数组,对数组中的每个元素执行传入的回调函数,并输出一个值。它对每个元素执行某些操作,并将计算结果记录在一个累加器变量中。当数组中没有剩余元素时,该方法返回累加器变量。
该reduce()函数本身接受两个输入:(a)reducer 函数或回调函数;(b)可选的起始点或initialValue。
reducer 函数或回调函数接受 4 个参数:accumulator,,,。currentItemindexarray
initialValue如果提供了可选参数,则accumulator第一次迭代时的值将等于initialValue输入currentItem数组中的第一个元素。否则,的值accumulator将等于输入数组中的第一个元素,而的值currentItem将等于数组中的第二个元素。
听起来很复杂?我们来看两个例子:
例 1
(i)给定一个数字数组,求出数组中每个元素的总和,并将其记录到控制台。
解决方案:
const givenArray = [1, 2, 3, 4, 5];
const sum = givenArray.reduce((acc, curr) => acc + curr);
console.log(sum); // console: 15
我们来看一下累加器和当前值……:
- 在第一次迭代中:
acc=1(givenArray[0]),curr=2(givenArray[1]) - 在第二次迭代中:
acc=3(givenArray[0] + givenArray[1]),curr=3(givenArray[2]) - 在第三次迭代中
acc=6(givenArray[0] + givenArray[1] + givenArray[2]):curr=4(givenArray[3]) - 在第四次迭代时
acc=10(givenArray[0] + givenArray[1] + givenArray[2] + givenArray[3]):curr=5(givenArray=[4]) - 最后:(
acc=15所有元素的总和)(数组迭代结束)
console.log您可以通过在函数内部运行如下代码来查看此结果:console.log("iteration: acc="+acc+" curr="+curr);
(ii) 给定一个数字数组,求出数组中每个元素(从 8 开始)的总和,并将结果输出到控制台。
解决方案:
const givenArray = [1, 2, 3, 4, 5];
const sum = givenArray.reduce((acc, curr) => acc + curr, 8);
console.log(sum); // console: 23
注意:这里,我们向函数传递了一个可选initialValue参数reduce(),表明我们希望从 8 开始,并在回调函数内部执行任何我们想要的操作。同样,您可以通过添加类似上面的代码来测试`and`和 `and`
的值。acccurrconsole.log
例 2
给定一个数字数组,求它们的平均值,并将结果记录到控制台。
解决方案:
const givenArray = [1, 2, 3, 456, 108115, 45909.15154, 1988.1545, 145e8];
const average = (givenArray.reduce((acc, curr) => acc + curr)) / givenArray.length;
console.log(average); // console: 1812519559.288255
如果你对第三行感到困惑,它基本上是先计算总和,然后将返回值除以字符串的长度givenArray。你也可以使用:
const givenArray = [1, 2, 3, 456, 108115, 45909.15154, 1988.1545, 145e8];
const average = givenArray.reduce((acc, curr, index) => ( index == (givenArray.length -1) ) ? (acc + curr) / givenArray.length : acc + curr);
console.log(average); // console: 1812519559.288255
这完全违背了可读性和KISS原则,但我又不是警察,你想用什么方法都行😉
Array.prototype.forEach
该forEach方法与语法类似for(let i = 0; i < array.length, i++){}。它会遍历数组,并对数组中的每个元素运行给定的回调函数。
传递给函数的回调函数forEach可以接受currentItem,, index。array
例子
给定一个数字数组,将每个数字记录到控制台(什么?!)。
解决方案:
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
arr.forEach(val => console.log(val));
/* console:
1
2
3
4
5
6
7
8
*/
map` and`方法之间的主要区别forEach在于,`and`map方法会创建一个新数组,将回调函数的返回值“映射”并创建一个新数组,而 `and`forEach方法只是遍历数组。
Array.prototype.some和Array.prototype.every
该some方法测试数组中是否至少有一个元素符合回调函数中给定的测试,并返回 truetrue或 false false。
传递给函数的回调函数some可以接受currentItem,, index。array
例 1
给定两个数字数组,测试每个数组是否至少有一个大于 5 的数字,并将结果记录到控制台。
解决方案:
const givenArray1 = [1, 2, 3, 5, 8];
const givenArray2 = [1, 2, 3, 4, 5];
const testArray1 = givenArray1.some(n => n > 5);
const testArray2 = givenArray2.some(n => n > 5);
console.log(`givenArray1: ${testArray1}; givenArray2: ${testArray2}`); // console: givenArray1: true; givenArray2: false
该every方法与另一个方法非常相似some,但它会测试数组中的所有元素是否都符合回调中给定的测试,并返回 truetrue或 false false。
传递给函数的回调函数every可以接受currentItem,, index。array
例 2
给定两个数字数组,测试每个数组中是否所有数字都大于等于 5,并将结果记录到控制台。
解决方案:
const givenArray1 = [10, 9, 8, 7, 6];
const givenArray2 = [5, 1, 2, 785, 45];
const testArray1 = givenArray1.every(n => n > 5);
const testArray2 = givenArray2.every(n => n > 5);
console.log(`givenArray1: ${testArray1}; givenArray2: ${testArray2}`); // console: givenArray1: true; givenArray2: false
Array.prototype.flat和Array.prototype.flatMap
该flat方法会创建一个包含所有元素的新数组,如果元素本身也是一个数组,则会将该元素“扁平化”,并将所有子数组元素添加到返回的数组中。默认情况下,它只会将数组扁平化到第一层。
该flat方法只能接受一个可选参数,depth即数组将被“扁平化”的级别或上限。
例 1
给定一个数字数组的数组,求出数组及其子数组中每个数字的总和,并将总和记录到控制台。
解决方案:
const givenArray = [
[1, 2, 3, 4, 5, 6],
[10, 20, 30, 40, 50, 60],
[100, 200, 300, 400, 500, 600]
];
const sum =
givenArray
.flat() // flattens the array
.reduce((acc, curr) => acc + curr); // finds the sum
console.log(sum); // console: 2331
该flatMap方法结合了两种flat方法map。它首先“扁平化”数组,然后对每个元素运行回调函数并将返回值“映射”到对应的元素,最后返回“扁平化并映射”后的数组。如果您使用类似这样的语句:arr.flatMap(...),它等价于arr.flat().map(...)。但是,需要注意一点:您不能扁平化数组超过一层,为此您需要使用.flat(...).map(...)语法。
该flatMap方法接受与方法相同的参数map,回调函数也是如此。
例 2
给定一个用户数组的数组,创建一个新数组,其中包含所有用户的名字列表,并将其记录到控制台。
解决方案:
const users = [
[
{ "firstName": "Lorem", "lastName": "Ipsum" },
{ "firstName": "Dolor", "lastName": "Sit" },
{ "firstName": "Amet", "lastName": "Consectetur" }
],
[
{ "firstName": "Adipiscing", "lastName": "Elit" },
{ "firstName": "Etiam", "lastName": "Lobortis" },
{ "firstName": "Lorem", "lastName": "Elit" }
],
[
{ "firstName": "Lorem", "lastName": "Ipsum" },
{ "firstName": "Dolor", "lastName": "Sit" },
{ "firstName": "Amet", "lastName": "Consectetur" }
],
[
{ "firstName": "Adipiscing", "lastName": "Elit" },
{ "firstName": "Etiam", "lastName": "Lobortis" },
{ "firstName": "Lorem", "lastName": "Elit" }
]
];
const usersFirstNames = users.flatMap(usersGroup => usersGroup.map(u => u.firstName));
console.log(usersFirstNames); // console: ["Lorem", "Dolor", "Amet", "Adipiscing", "Etiam", "Lorem", "Lorem", "Dolor", "Amet", "Adipiscing", "Etiam", "Lorem"]
Array.prototype.find
该find方法返回数组中第一个满足回调函数中布尔测试的元素。如果没有元素通过布尔测试,undefined则返回空值。
传递给该函数的回调函数find可以接受以下三个参数中的任何一个:item,,index。array
例子
给定一个包含水果的数组,找出所有“苹果”,并将对应的对象记录到控制台。
解决方案:
const fruits = [
{"name": "bananas", "quantity": 8},
{"name": "cherries", "quantity": 3},
{"name": "apples", "quantity": 80}
];
const apples = fruits.find( ({name}) => name == "apples" );
console.log(apples); // console: {"name": "apples", "quantity": 80}
Array.prototype.sort
该sort方法顾名思义:它对数组进行原地“排序”,并返回排序后的数组。默认排序顺序为升序。
注意“原地”这个词。这意味着原始数组会被修改,但返回的数组引用不变。所以,originalArray===newArray如果没有排序,则不会发生这种情况。
它接受一个函数,该函数指定排序标准。
例 1
给定一个数字数组,按升序对数组进行排序,并将排序后的数组输出到控制台。
解决方案:
const givenArray = [4, 5, 2, 1, 3];
givenArray.sort((a, b) => a - b);
console.log(givenArray);
例 2
给定一个联系人数组,按姓名字母顺序对其进行排序,并将排序后的数组记录下来。
解决方案:
const givenArray = [
{"name": "Yosha Gamuda", "phone": 1234567890},
{"name": "Portia Umeng", "phone": 4894759371},
{"name": "Yosha Gamuda", "phone": 1234567890},
{"name": "Portia Umeng", "phone": 4894759371}
];
givenArray.sort(({name1}, {name2}) => {
name1 = name1.toUpperCase();
name2 = name2.toUpperCase();
return (name1 < name2) ? -1 : (name1 > name2) ? 1 : 0);
});
console.log(givenArray);
它的工作方式sort()与其他方式略有不同。引用MDN文档:
如果提供了 compareFunction 函数,则所有非 undefined 数组元素将根据 compareFunction 函数的返回值进行排序(所有 undefined 元素将排序到数组末尾,且不调用 compareFunction)。如果 a 和 b 是要比较的两个元素,则:
- 如果 compareFunction(a, b) 返回小于 0,则将 a 排序到比 b 更小的索引(即 a 排在第一位)。
- 如果 compareFunction(a, b) 返回 0,则 a 和 b 彼此之间保持不变,但对所有不同的元素进行排序。注意:ECMAScript 标准直到 2019 年才开始保证这种行为,因此,旧版浏览器可能不支持此行为。
- 如果 compareFunction(a, b) 返回大于 0,则将 b 排序到比 a 更小的索引(即 b 排在第一位)。
- compareFunction(a, b) 必须始终返回相同的值,无论给定的是给定的两个元素 a 和 b。如果返回的结果不一致,则排序顺序未定义。
要比较数字而不是字符串,比较函数可以从 a 中减去 b。以下函数将按升序对数组进行排序(如果它不包含无穷大和 NaN)。
结论
我知道这篇文章的信息量非常庞大。当然还有很多其他的文章,但总的来说,你不需要了解Array.prototype数组的每一个方法。感谢阅读本文,希望你喜欢。任何反馈我都非常感激:无论好坏 ;)