前言
先看看下面这段代码:(重点关注两函数的实现方式,无需细看实现逻辑)
function getAreaSale1(values, areas) {
const areaSale = [];
areas.forEach(area => {
let sum = values.reduce((acc, cur) => {
if (cur.area === area) {
acc[area] === undefined ? acc[area] = cur.sale : acc[area] += cur.sale;
}
return acc;
}, {});
areaSale.push(sum);
})
return areaSale;
}
function getAreaSale2(values, areas) {
const areaSale = [];
for (let i = 0; i < areas.length; i++) {
let sum = {};
for (let j = 0; j < values.length; j++) {
if (values[j].area === areas[i]) {
sum[areas[i]] === undefined ? sum[areas[i]] = values[j].sale : sum[areas[i]] += values[j].sale;
}
}
areaSale.push(sum);
}
return areaSale;
}
function main() {
const values = [
{
area: '西安',
sale: 123
},
{
area: '咸阳',
sale: 234
},
{
area: '西安',
sale: 345
},
{
area: '宝鸡',
sale: 456
},
{
area: '铜川',
sale: 567
},
{
area: '铜川',
sale: 678
},
{
area: '宝鸡',
sale: 789
},
]
const areas = ['西安', '咸阳', '宝鸡', '铜川'];
console.log(getAreaSale2(values, areas));
}
getAreaSale1函数与getAreaSale2函数的功能一模一样,只不过getAreaSale1函数显得更加有格调一些。
不知道大家有发现没,那些大佬以及源码里所产出的代码里很难看到传统的fori循环,所以本篇博客就是教你如何使用Array中的现有API取代传统的fori循环,从而让自己的代码看起来更像“源码”!
也许这些API的性能不及传统的fori循环高效,但是在绝大多数情况下是相差无几。换句话说,很多时候明明可以使用API简单处理的问题而自己却使用fori循环去实现此API的部分功能来解决问题,此做法就是变相重复造轮子。
正文
以下所有API的讲解我都会结合具体示例并对比传统fori循环进行叙述。
并且为了让大家对于API更有源码的直观感,以下所有的API内部函数的调用我都使用箭头函数的方式。
foreach
foreach可以简单的理解为原始fori的API版本,遍历数组中的每个元素并在回调函数中执行自己的逻辑代码,无返回值。
foreach使用方式:
arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
show you my example:
const arraySparse = [1, 3, 8, 7];
arraySparse.forEach(element => console.log(element));
function foreach(arraySparse) {
for (let i = 0; i < arraySparse.length; i++) {
console.log(arraySparse[i]);
}
}
every
every基于遍历所有数组元素的基础上,并判断其所有元素是否都能通过某个指定函数的测试,结果返回一个布尔值。
every的使用方式:
arr.every(callback(element[, index[, array]])[, thisArg])
show you my example:
const arraySparse = [1, 3, 8, 7];
const result = arraySparse.every(element => element <= 8);
function every(arraySparse) {
for (let i = 0; i < arraySparse.length; i++) {
if (arraySparse[i] > 8) {
return false;
}
}
return true;
}
filter
filter方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素,不改变原数组内容。
filter的使用方式:
const newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
show you my example:
const arraySparse = [1, 3, 8, 7];
const filterArray = arraySparse.filter(element => element > 5);
function filter(arraySparse) {
const filterArray = [];
for (let i = 0; i < arraySparse.length; i++) {
if (arraySparse[i] > 5) {
filter.push(arraySparse[i]);
}
}
return filterArray;
}
find
find方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
find的使用方式:
arr.find(callback[, thisArg])
show you my example:
const arraySparse = [1, 3, 8, 7];
const findArray = arraySparse.find(element => element > 5);
function find(arraySparse) {
for (let i = 0; i < arraySparse.length; i++) {
if (arraySparse[i] > 5) {
return arraySparse[i];
}
}
return undefined;
}
map
map方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值,不改变原数组内容。
map的使用方式:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
show you my example:
const arraySparse = [1, 3, 8, 7];
const mapArray = arraySparse.map(element => element + 5);
function map(arraySparse) {
const mapArray = [];
for (let i = 0; i < arraySparse.length; i++) {
mapArray.push(arraySparse[i] + 5);
}
return mapArray;
}
some
some方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
some的使用方式:
arr.some(callback(element[, index[, array]])[, thisArg])
show you my example:
const arraySparse = [1, 3, 8, 7];
const someArray = arraySparse.some(element => element > 8);
function some(arraySparse) {
for (let i = 0; i < arraySparse.length; i++) {
if (arraySparse[i] > 8) {
return true;
}
}
return false;
}
注:some方法和every方法恰好相反。
reduce
reduce方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
reduce的使用方式:
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
show you my example:
const arraySparse = [1, 3, 8, 7];
const reduceArray = arraySparse.reduce((acc, cur) => acc + cur, -1);
function reduce(arraySparse, index) {
let acc = index;
for (let i = 0; i < arraySparse.length; i++) {
const cur = arraySparse[i];
acc += cur;
}
return acc;
}
小结
上述7种API都有回调函数的功能,其实这个回调函数的代码就是fori循环里的逻辑代码,比如foreach,只不过更多的API相对于fori循环已经帮助我们实现了特定的逻辑代码。看完上述7种API与fori的案例对比,是不是瞬间感觉自己制造了不少重复的轮子。
上述讲述时所给出的案例都是一些最基本的单一应用案例,复杂的案例也不过是换汤不换药,比如文中最开始给的案例,使用foreach+reduce取代fori循环。
最后,熟练掌握这7种API就足矣替代90%及其以上情形的fori循环,至于剩下10%的情形也不是因为无法替代而是使用传统的fori循环效率明显会更高,比如如下的这个案例:
function main() {
const values = [
{
area: '西安',
sale: 123
},
{
area: '咸阳',
sale: 234
},
{
area: '宝鸡',
sale: 456
},
{
area: '铜川',
sale: 567
},
{
area: '西安',
sale: 345
},
{
area: '咸阳',
sale: 890
},
{
area: '宝鸡',
sale: 789
},
{
area: '铜川',
sale: 678
},
]
const areas = ['西安', '咸阳', '宝鸡', '铜川'];
}
稍微更改一下最开始那个案例的数据,只不过这次我想要得到的是如下的结果:
const result = [
[
{
area: '西安',
sale: 123
},
{
area: '西安',
sale: 345
}
],
[
{
area: '咸阳',
sale: 234
},
{
area: '咸阳',
sale: 890
}
],
[
{
area: '铜川',
sale: 567
},
{
area: '铜川',
sale: 678
}
],
[
{
area: '宝鸡',
sale: 456
},
{
area: '宝鸡',
sale: 789
}
]
]
此时这种case的数据使用传统的fori循环进行处理效果明显更高,至于原因应该不难想到。
结语
到此,本篇博客的内容就叙述完毕,正文并没有详细的讲解此API的用法,重点在于API与fori循环的使用对比,如果有对API使用有疑惑的朋友,可以参看mdn官方文档进行API学习:Array API使用文档
相信看完本篇博客之后的朋友能够对此类API的使用更加熟练,希望日后每当要使用fori循环时能够第一时间思考到是否可以使用API进行问题处理,从而使自己的代码观感更上一层楼。