前端修仙之路

js函数实现:forEach、map、reduce

2019-07-03  本文已影响2人  月上秦少

先认识JS的ArrayforEachmapreduce方法:

因为typescript中有类型标注,我们看一下ts中的定义:
typescript下的定义:

/**
 * Performs the specified action for each element in an array.
 * @param callbackfn  A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.
 * @param thisArg  An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
 */
forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;

/**
 * Calls a defined callback function on each element of an array, and returns an array that contains the results.
 * @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
 * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
 */
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];

/**
 * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
 * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
 * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
 */
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;

接下来我们小试牛刀,理解forEachmapreduce方法:

let arr = [
    {id: 1, name: 'Aom', age: 12},
    {id: 2, name: 'Bom', age: 13},
    {id: 3, name: 'Com', age: 14},
    {id: 4, name: 'Dom', age: 15},
    {id: 5, name: 'Eom', age: 16},
    ];

// forEach(callback, thisArgs)一般只会传入callback,thisArg很少用
// forEach的回调函数有三个参数,相当于for循环,返回undefined
// thisArg 可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。
//         如果省略了 thisArg,或者传入 null、undefined,那么回调函数的 this 为全局对象。
let value1 = arr.forEach((item, index, arr) => {
    // 执行
    console.log(`${item}:${index}`);
    return [item.id, item.age];
});
console.log(value1);  // undefined

// map(callback, thisArgs)一般只会传入callback,thisArg很少用 
// map的回调函数有三个参数,返回新的数组,不影响原数组
// thisArg 可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。
//         如果省略了 thisArg,或者传入 null、undefined,那么回调函数的 this 为全局对象。
let value2 = arr.map((item, index, arr) => {
    // 执行
    console.log(`${item}:${index}`);
    return {id: item.id,name: item.name};
});
console.log(value2);  // (5) [{…}, {…}, {…}, {…}, {…}]

// reduce接受两个参数:Array.reduce(callback(previousValue, currentValue, currentIndex?, arr?),initialValue?)
// reduce的回调函数有四个参数,返回聚合的结果,不影响原数组;将callback返回值作为下一次的previousValue
// reduce的initialValue如果存在的话,会作为第一个previousValue使用;否则将原数组中的第一个值作为第一个previousValue
let value3 = arr.reduce((previousValue, currentValue, currentIndex, arr) => {
    return previousValue.age + currentValue.age;
}, {id: 6, name: 'zkk', age: 18})

利用reduce实现统计数组中元素出现的个数:

Array.prototype.countElement = function() {
    return this.reduce((previousValue, currentValue) => {
        previousValue[currentValue] = previousValue[currentValue] ? ++previousValue[currentValue]: 1;
        return previousValue;
    },{})
}
// 使用
[1, 1, 2, 2, 3].countElement();
// {1: 2, 2: 2, 3: 1}

注意:由于箭头函数中没有this的,所以当callback为箭头函数时,传入的第二个参数(thisArg)是没有意义的。

下面来用forEach实现一个简单的map函数:

Array.prototype.myMap = function(callback) {
    var res = []; // 保存数据
    this.forEach(function(item, index, arr) { // this指代Array
        res.push(callback(item, index, arr)); // 将callback对原数组的每一项执行结果保存
    })
    return res;
}
// 使用
let arr = [
    {id: 1, name: 'Aom', age: 12},
    {id: 2, name: 'Bom', age: 13},
    {id: 3, name: 'Com', age: 14},
    {id: 4, name: 'Dom', age: 15},
    {id: 5, name: 'Eom', age: 16},
    ];
arr.myMap((item, index, arr) => {
    console.log(item, index, arr);
    return [item.age];
})

再来用reduce实现一个简单的map函数:

Array.prototype._map = function(callback){
    this.reduce((previousValue, currentValue, currentIndex, arr) => {
        previousValue.push(callback(currentValue, currentIndex, arr));
        return previousValue;
    }, []);
};

[1,2,3,4]._map((item, index, arr) => {
    console.log(item, index, arr);
    return item * 2;
})

最后,用forEach实现一个reduce方法:

Array.prototype._reduce = function(callback, initialValue){
    // 如果initialValue存在,previousValue为initialValue,否则为Array[0]
    let res = initialValue || this[0];  // this --> Array
    this.forEach((item, index, arr) => {
        if(initialValue) {
            res = callback(res, item, index, arr)
        } else{
            if(index+1 < arr.length){
                res = callback(res, arr[index+1], index+1, arr)
            }
        }
    })
    return res;
}

用自己实现的_reduce,实现统计数组中元素出现的个数:

Array.prototype.countElement = function() {
    return this._reduce((previousValue, currentValue) => {
        previousValue[currentValue] = previousValue[currentValue] ? ++previousValue[currentValue]: 1;
        return previousValue;
    },{})
};
// 使用
[1, 1, 2, 2, 3].countElement();
// {1: 2, 2: 2, 3: 1}
上一篇 下一篇

猜你喜欢

热点阅读