在 JavaScript 中,函数为一等公民(First Class),所谓的 “一等公民”,指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或作为其它函数的返回值。

  1. 函数赋值给变量 其实就是在《创建函数》一节中提到的函数表达式

image.png

  1. 函数作为参数

    1. // js内置对象Array的实例方法map()
    2. const array = [1, 2, 3, 4];
    3. const map = array.map(x => x * 2); // [2, 4, 6, 8]
  2. 函数作为其他函数的返回值

image.png

高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

  • 接受一个或多个函数作为输入;
  • 输出一个函数。

接收一个或多个函数作为输入,即函数作为参数传递。这种应用场景,相信很多人都不会陌生。比如常用的javascript内置对象Array的两个实例方法 Array.prototype.map()Array.prototype.filter() 都是高阶函数:


  1. // Array.prototype.map 高阶函数
  2. const array = [1, 2, 3, 4];
  3. const map = array.map(x => x * 2); // [2, 4, 6, 8]
  4. // Array.prototype.filter 高阶函数
  5. const words = ['semlinker', 'kakuqo', 'lolo', 'abao'];
  6. const result = words.filter(word => word.length > 5); // ["semlinker", "kakuqo"]

而输出一个函数,即调用高阶函数之后,会返回一个新的函数。我们日常工作中,常见的 debouncethrottle 函数就满足这个条件,因此它们也可以被称为高阶函数。

函数组合

函数组合就是将两个或两个以上的函数组合生成一个新函数的过程:

  1. const composeFn = function (f, g) {
  2. return function (x) {
  3. return f(g(x));
  4. };
  5. };

在以上代码中,fg 都是函数,而 x 是组合生成新函数的参数。

函数组合的作用

在项目开发过程中,为了实现函数的复用,我们通常会尽量保证函数的职责单一,比如我们定义了以下功能函数:

image.png

在拥有以上功能函数的基础上,我们就可以自由地对函数进行组合,来实现特定的功能:

  1. function lowerCase(input) {
  2. return input && typeof input === "string" ? input.toLowerCase() : input;
  3. }
  4. function upperCase(input) {
  5. return input && typeof input === "string" ? input.toUpperCase() : input;
  6. }
  7. function trim(input) {
  8. return typeof input === "string" ? input.trim() : input;
  9. }
  10. function split(input, delimiter = ",") {
  11. return typeof input === "string" ? input.split(delimiter) : input;
  12. }
  13. const trimLowerCaseAndSplit = compose(trim, lowerCase, split); // 参考下面compose的实现
  14. trimLowerCaseAndSplit(" a,B,C "); // ["a", "b", "c"]

在以上的代码中,我们通过 compose 函数实现了一个 trimLowerCaseAndSplit 函数,该函数会对输入的字符串,先执行去空格处理,然后在把字符串中包含的字母统一转换为小写,最后在使用 , 分号对字符串进行拆分。利用函数组合的技术,我们就可以很方便的实现一个 trimUpperCaseAndSplit 函数。

组合函数的实现

  1. function compose(...funcs) {
  2. return function (x) {
  3. return funcs.reduce(function (arg, fn) {
  4. return fn(arg);
  5. }, x);
  6. };
  7. }

在以上的代码中,我们通过 Array.prototype.reduce 方法来实现组合函数的调度,对应的执行顺序是从左到右。这个执行顺序与 Linux 管道或过滤器的执行顺序是一致的。

image.png

不过如果你想从右往左开始执行的话,这时你就可以使用 Array.prototype.reduceRight 方法来实现。