写作不易,Star是最大鼓励,感觉写的不错的可以给个Star⭐,请多多指教。本博客的Github地址

什么是函数式编程

函数式是一种编程形式,我们可以将函数作为参数传递给其他函数,也可以将函数作为返回值返回,还可以在将函数作为参数的同时,再将函数作为返回值返回。 在函数式编程中,我们以函数的形式思考和编程。

高阶函数

在JS中,函数是一种特殊类型的对象,它们是Function objects。我们可以像给对象添加属性一样给函数添加属性,但是不推荐这样做。 高阶函数是对其他函数进行操作的函数,操作可以是将它们作为参数,或者是返回它们。 简单来说,满足以下任何一点的都属于高阶函数:

  1. 接受一个或多个函数作为参数;
  2. 返回一个函数。

在js中内置了一些高阶函数,比如数组的map、forEach、reduce等。

函数作为参数传递

Array.prototype.map

举个🌰:现有一个数组[1, 2, 3],我们想要基于该数组来生成一个新数组,其新数组中每个元素都是之前数组的两倍,分别使用高阶和不使用高阶函数的方式来实现。代码如下:

不使用高阶函数:

const arr1 = [1, 2, 3];
const arr2 = [];
for (let i = 0; i < arr1.length; i++) {
  arr2.push(arr1[i] * 2);
}

console.log(arr1); // [ 1, 2, 3 ]
console.log(arr2); // [ 2, 4, 6 ]
1
2
3
4
5
6
7
8

使用map高阶函数:

const arr1 = [1, 2, 3];

const arr2 = arr1.map(item => item * 2);

console.log(arr1); // [ 1, 2, 3 ]
console.log(arr2); // [ 2, 4, 6 ]
1
2
3
4
5
6

Array.prototype.filter

举个🌰:现在有一个数组[1, 2, 3, 2, 3, 1, 4, 4, 5, 5],我们想要生成一个新数组,这个数组要求没有重复的内容,即为去重。

不使用高阶函数:

const arr = [1, 2, 3, 2, 3, 1, 4, 4, 5, 5];
const arr2 = [];

for (let i = 0; i < arr.length; i++) {
    if (arr.indexOf(arr[i]) === i) {
        arr2.push(arr[i]);
    }
}
console.log(arr); // [ 1, 2, 3, 2, 3, 1, 4, 4, 5, 5 ]
console.log(arr2); // [ 1, 2, 3, 4, 5 ]
1
2
3
4
5
6
7
8
9
10

使用filter高阶函数:

const arr = [1, 2, 3, 2, 3, 1, 4, 4, 5, 5];
const arr2 = arr.filter((item, index, sourceArray) => {
    if (sourceArray.indexOf(item) === index) {
        return item;
    }
});
console.log(arr); // [ 1, 2, 3, 2, 3, 1, 4, 4, 5, 5 ]
console.log(arr2); // [ 1, 2, 3, 4, 5 ]
1
2
3
4
5
6
7
8

函数作为返回值输出

判断类型函数

const types = ['Number', 'String','Object','Array','Null','Undefined','Boolean'];

const util = {};
const isType = type => obj => Object.prototype.toString.call(obj).includes(type);
types.forEach(type => {
    util[`is${type}`] = isType(type);
});

console.log(util.isString('test')); // true
console.log(util.isString(123)); // false
1
2
3
4
5
6
7
8
9
10

add 函数

add(1); // 1
add(1)(2);  // 3
add(1)(2)(3)// 6
add(1)(2)(3)(4)// 10

// 以此类推
1
2
3
4
5
6

我们知道打印函数时会自动调用toString()方法,函数add(a)返回一个闭包sum(b),函数sum中累加计算a += b,只需要重写sum.toString()方法返回变量a就可以了。

function add(a) {
    function sum(b) {
        a += b;
        return sum; // 链式调用
    }
    sum.toString = function() {
        return a;
    }
    return sum;
}

add(1);
1
2
3
4
5
6
7
8
9
10
11
12

高阶函数优点

  1. 使我们的代码更加清晰简洁;

高阶函数实现

举个🌰:假设我们有一个字符串数组,我们希望把它转换为整数数组,其中每个元素代表原始数组中字符串的长度。实现代码如下:

const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C'];

Array.prototype.mapForEach = function(cb) {
    const arr = this;
    const res = [];
    if (!Array.isArray(arr)) {
        throw new TypeError('type error');
    }
    for (let i = 0; i < arr.length; i++) {
        res.push(cb(arr[i]));
    }
    return res;
}

const res = strArray.mapForEach(item => item.length);

console.log(res); // [ 10, 6, 3, 4, 1 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

参考文档

  1. 理解 JavaScript 中的高阶函数
  2. Understanding Higher-Order Functions in JavaScript
  3. 高阶函数详解与实战
  4. 【JS必知必会】高阶函数详解与实战
  5. 高阶函数应用