数组的forEach,map,filter,reduce,reduceRight,every,some方法

1,940 阅读5分钟

forEach

基本介绍

forEach按照升序为数组中的每一项执行依此callback函数,那些已删除或未初始化的项将被跳过(被显式声明为undefined的同样会被处理)

var a = [1,2, ,3], b = [1,2,undefined,3];
a.forEach(function(item){
    console.log(item);
});
//依次输出1,2,3

b.forEach(function(item){
    console.log(item);
});
//依此输出1,2,undefined,3

arr.forEach(callback[, thisArg]);

callback:为数组中每个元素执行的函数,且总是返回undefined
currentValue:正在处理的当前元素
(可选)index:正在处理的当前元素的索引
(可选)array:正在处理的数组
(可选)thisArg:执行callback时用作this的值

遍历范围

forEach遍历的范围在第一次调用callback前就会确定

var a = [1,2];
a.forEach(function(current, i, arr){
    arr.push(current);
    console.log(current);
})
//依次打印1,2

自己做了以下的测试

var a = [1, 2,,3];
var count = 0;
a.forEach(function (current, i, arr) {
    count++;
})
console.log(count);//输出3

var a = [1, 2,,3];
var count = 0;
a.forEach(function (current, i, arr) {
    arr[i+1] = current+1;
    count++;
})
console.log(count);//输出4

上述的代码跟之前总结的有点不太一样啊?!forEach遍历的范围不是在第一次调用callback前就确定的吗?那那些没有初始化的为什么还会执行呢?难道是我理解错了?
我思考了一下,觉得forEach方法的执行是这样的:

首先会根据数组的长度来确认循环的次数,这里是4次
每次callback执行之前,都会去判断当前处理的元素是否已定义,如果未定义,那么不会执行callback直接跳到下一个处理的元素

forEach遍历的值是实时的,即如果已经存在的值被改变,则传递给callback的值是forEach遍历到他们那一刻的值

var a = [1,2];
a.forEach(function(current, i, arr){
    arr[i+1] = current;
    console.log(current);
})
//依次打印1,1

以上的执行过程也是符合前面的总结的

简单实现

Array.prototype.fakeForEach = function(fn, thisArg){
    let arr = this;
    let len = arr.length;
    for(let i=0; i<len; i++){
        if(i in arr){//判断当前的index是否已初始化
            fn.call(thisArg, arr[i], i, arr);
        }
    }
}

map

基本介绍

map方法创建一个新的数组,其结果是该数组中每一个元素都调用一个提供的函数后返回的结果。

var a = [1,2,3];
var aa = map((current)=>{
    return current*current;
});
console.log([1,4,9]);

arr.map(callback[, thisArg]);同forEach

遍历范围同forEach

相关题目

['1','2','3'].map(parseInt);//结果是[1,NaN,NaN]   

parseInt(string, radix);//该函数返回以radix未基数解析的string整数
执行以上代码时具体步骤如下

parseInt('1', 0);//默认以解析十进制返回1
parseInt('2', 1);//1进制中没有2,返回NaN
parseInt('3', 2);//2进制中没有3,返回NaN
返回[1,NaN,NaN]

简单实现

Array.prototype.fakeMap = function(fn, thisArg){
    let arr = this;
    let len = arr.length;
    let newArr = new Array(len);
    for(let i=0; i<len; i++){
        if(i in arr){//判断当前的index是否已初始化
            newArr[i] = fn.call(thisArg, arr[i], i, arr);
        }
    }
    return newArr;
}

reduce实现map

Array.prototype.fakeMap = function(fn, thisArg){
    let arr = this;
    let newArr = arr.reduce(function (newArr, current, i, arr){
        let o = fn.call(thisArg, current, i, arr);
        newArr.push(o);
        return newArr;
    },[])
    return newArr;
}

filter

基本介绍

filter方法创建一个新的数组,其包含执行callback后返回值为true的所有元素

let arr = [1,2,3];
var newArr = arr.filter(function(item, i, arr){
    return item != 2;
});
newArr;//[1,3]

arr.filter(callback[, thisArg]);同forEach

遍历范围同forEach

简单实现

Array.prototype.fakeFilter = function(fn, thisArg){
    let arr = this;
    let len = arr.length;
    let newArr = [];
    for(let i=0; i<len; i++){
        if(i in arr){//判断当前的index是否已初始化
            if(fn.call(thisArg, arr[i], i, arr)){
                newArr.push(arr[i])
            }
        }
    }
    return newArr;
}

reduce

基本介绍

reduce方法按升序对数组中每个元素执行callback,将accumulator赋值为callback返回结果,返回最后的accumulatorreduce返回值

let arr = [1,2,3];
//对arr数组求和
let result = arr.reduce(function(accumulator, current, i, arr){
    return accumulator+current;
});
result;//6

arr.reduce(callback(accumulator, currentValue[ index [,array]]) [,initialValue]);

callback:为数组中每个元素执行的函数,且总是返回undefined
accumulator:累加器,它是上一次调用回调函数时返回的累积值
currentValue:正在处理的当前元素
(可选)index:正在处理的当前元素的索引
(可选)array:正在处理的数组
(可选)initialValue:作为第一次执行callback时的值
返回值为最后一次执行callback的返回值

遍历范围

大体上与forEach相同,遍历流程不同之处如下

初始化执行次数n,有initialValue则赋值给accumulator,没有则arr[0]赋值给accumulator
执行callback,将返回值赋值给accumulator × n
将最后一次执行callback的返回值返回

应用

按顺序执行Promise

function runPromiseInOther(promiseArr, initialValue){
    return promiseArr.reduce(function(result, current){
            return result.then(current);
        }, Promise.resolve(initialValue)
    );
}
function p1(lastValue){
    return new Promise(function(resolve, reject){
        console.log(lastValue);
        resolve(lastValue * 10);
    })
}
function p2(lastValue){
    return new Promise(function(resolve, reject){
        console.log(lastValue);
        resolve(lastValue * 100)
    })
}
runPromiseInOther([p1,p2], 1)
    .then(console.log);
//依次输出1,10,1000

简单实现

arr.prototype.reduce(function(a, c, i, arr){return a+c;}, initialValue)
Array.prototype.fakeReduce = function(fn, initialValue){
    let arr = this;
    let len = arr.length;
    let i=0, result;
    if(arguments.length == 1){
        result = arr[0];
        i=1
    }else{
        result = initialValue;
    }
    for(; i<len; i++){
        if(i in arr){
            result = fn(result, arr[i], i, arr);
        }
    }
    return result;
}

every

基本介绍

every() 方法测试数组的所有元素是否都通过了指定函数的测试,如果测试callback有返回false则立即返回,后续的代码不会被执行

let arr = [1,2,3];
console.log(
    arr.every(function(current){
        return current < 10;
    })
);//输出true

arr.every(callback[, thisArg]);同forEach

遍历范围同forEach

简单实现

Array.prototype.fakeEvery = function(fn, thisArg){
    let arr = this;
    let len = arr.length;
    for(let i=0; i<len; i++){
        if(i in arr){//判断当前的index是否已初始化
            if(!fn.call(thisArg, arr[i], i, arr)){
                return false;
            }
        }
    }
    return true;
}

some

基本介绍

some()方法测试是否至少有一个元素通过由提供的函数实现的测试,如果测试callback有返回true则立即返回,后续的代码不会被执行。

let arr = [1,2,3];
console.log(
    arr.some(function(current){
        return current < 2;
    })
);//输出true

arr.some(callback[, thisArg]);同forEach

遍历范围同forEach

简单实现

Array.prototype.fakeEvery = function(fn, thisArg){
    let arr = this;
    let len = arr.length;
    for(let i=0; i<len; i++){
        if(i in arr){//判断当前的index是否已初始化
            if(fn.call(thisArg, arr[i], i, arr)){
                return true;
            }
        }
    }
    return false;
}

总结

  1. 不能使用break来跳出循环
  2. 都是按照升序来遍历的
  3. 执行流程大致相同,具体看forEach的分析
  4. 实现的思路为len初始化,for实现遍历,in判断是否已初始化,fn.call调用函数

参考材料:MDN
总结有错还请指出,谢谢