一文搞懂JS Array迭代原理
//【问题引入1】两个变量,两个函数,两两配对通过for循环进行操作,返回经过处理后等长的数组,会出现代码冗余的情况
function oodlify(s) {
return s.replace(/[aeiou]/g, 'oodle');
}
function izzlify(s) {
return s.replace(/[aeiou]+/g, 'izzle');
}
const fellowship = [
'frodo',
'sam',
'gandalf',
'aragorn',
'boromir',
'legolas',
'gimli',
];
const band = [
'John',
'Paul',
'George',
'Ringo',
];
function oodlifyArray(input) {
let output = [];
for (let item of input) {
let newItem = oodlify(item);
output.push(newItem);
}
return output;
}
function izzlifyArray(input) {
let output = [];
for (let item of input) {
let newItem = izzlify(item);
output.push(newItem);
}
return output;
}
let bandoodle = oodlifyArray(band);
let bandizzle = izzlifyArray(band);
let fellowshipoodle = oodlifyArray(fellowship);
let fellowshipizzle = izzlifyArray(fellowship);
//因此可以抽象出一个通过的模式,给定一个函数和一个数组,通过这个函数,把数组中每一个元素做操作后放到新的数组里。
//注意:map 并没有覆盖到每一种可能需要用到的循环。只有当你想创建一个和输入数组同样长度的数组时才有用。
function map_for(f,a){
let output=[]
for(let item of a){
output.push(f(item))
}
return output
}
function map_recursion(f,a){
if(a.length ===0){return [];}
return [f(a[0]).concat(map(f,a.slice(1)))]
}
//【问题引入2】如果你想要向数组中增加几个元素呢?或者想找一个列表中的最短字符串是哪个?其实有时我们对数组进行处理,最终只想得到一个值而已。
const heroes1 = [
{name: 'Hulk', strength: 90000},
{name: 'Spider-Man', strength: 25000},
{name: 'Hawk Eye', strength: 136},
{name: 'Thor', strength: 100000},
{name: 'Black Widow', strength: 136},
{name: 'Vision', strength: 5000},
{name: 'Scarlet Witch', strength: 60},
{name: 'Mystique', strength: 120},
{name: 'Namora', strength: 75000},
];
//找到最强壮的
let strongest = {strength: 0};
for (hero of heroes1) {
if (hero.strength > strongest.strength) {
strongest = hero;
}
}
//保存所有英雄的总能量
let combinedStrength = 0;
for (hero of heroes1) {
combinedStrength += hero.strength;
}
//两个的功能都是对数组进行处理,最终得到一个值。所以,我们创建一个 reduce 函数来封装这个模式。
//注意:没有人说 reduce 方法只能返回基本类型,它可以是一个 object 类型,甚至可以是另一个数组
function reduce(f,initialVal,a){
let working=initialVal;
for(let item of a ){
working=f(working,item);
}
return working;
}
//【问题引入3】现在我们有了 map 处理数组中的每个元素,有了 reduce 可以处理数组最终得到一个值。但是如果想获取数组中的某些元素该怎么办?
const heroes2 = [
{name: 'Hulk', strength: 90000, sex: 'm'},
{name: 'Spider-Man', strength: 25000, sex: 'm'},
{name: 'Hawk Eye', strength: 136, sex: 'm'},
{name: 'Thor', strength: 100000, sex: 'm'},
{name: 'Black Widow', strength: 136, sex: 'f'},
{name: 'Vision', strength: 5000, sex: 'm'},
{name: 'Scarlet Witch', strength: 60, sex: 'f'},
{name: 'Mystique', strength: 120, sex: 'f'},
{name: 'Namora', strength: 75000, sex: 'f'},
];
// //找到所有的女性英雄
// let femaleHeroes = [];
// for (let hero of heroes2) {
// if (hero.sex === 'f') {
// femaleHeroes.push(hero);
// }
// }
// //找到所有能量大于500的英雄
// let superhumans = [];
// for (let hero of heroes2) {
// if (hero.strength >= 500) {
// superhumans.push(hero);
// }
// }
//逻辑严密,看起来还不错?但是里面又出现了重复的情况。实际上,区别在于 if 的判断语句,那么能不能把 if 语句重构到一个函数中呢?
//断言函数predicate(只返回true和false的函数)
function isFemaleHero(hero) {
return (hero.sex === 'f');
}
function isSuperhuman(hero) {
return (hero.strength >= 500);
}
let femaleHeroes = [];
for (let hero of heroes2) {
if (isFemaleHero(hero)) {
femaleHeroes.push(hero);
}
}
let superhumans = [];
for (let hero of heroes2) {
if (isSuperhuman(hero)) {
superhumans.push(hero);
}
}
//两个的功能都是对数组进行处理,最终得到一个值其子数组。所以,我们创建一个 filter函数来封装这个模式。
function filter(predicate,a){
let working=[]
for(let item of a ){
if(predicate(item)){
working=working.concat(item)
}
}
}
//【问题引入4】只想返回一个英雄。
//用filter就可以这样
const blackWidow=heroes2.filter((item)=>{
return item.name == 'Black Widow'
})
console.log(blackWidow)
//存在一个问题,效率太低,如果找到了还会继续匹配后面的元素,因此,依旧利用断言函数,我们写一个 find 函数来返回第一次匹配上的元素。
function find(predicate,a){
for(let item of a ){
if(predicate(item)){
return item
}
}
}