高阶函数与一等公民

210 阅读3分钟

高阶函数 Higher-Order Functions

一个函数接收另一个函数作参数或者返回一个新的函数,被称作高阶函数

一般的函数都是对string、number、boolean等等类型进行处理,而它是对函数进行处理,可以理解为js世界里的督察(管理警察的警察👮)。

一等公民

《Programming Language Pragmatics》中的定义是

In general, a value in a programming language is said to have first-class status if it can be passed as a parameter, returned from a subroutine, or assigned into a variable. 通常,如果一个值它可以作为一个参数传递,可以被函数返回,可以被存储在变量中,那它就被称为一等公民。

哪些是一等公民

一般在主流编程语言里,string、number、boolean、object、array五种类型是作为一等公民存在的。

处理string类型数据

sayHi = (name) => `Hi, ${name}!`;
result = sayHi('User');

console.log(result); // 'Hi, User!'

处理number类型数据

double = (x) => x * 2;
result = double(4);

console.log(result); // 8

处理boolean类型数据

getClearance = (allowed) => (allowed ? 'Access granted' : 'Access denied');

result1 = getClearance(true);
result2 = getClearance(false);

console.log(result1); // 'Access granted'
console.log(result2); // 'Access denied'

处理对象(object)类型数据

getFirstName = (obj) => obj.firstName;

result = getFirstName({
  firstName: 'Yazeed'
});

console.log(result); // 'Yazeed'

处理数组(array)类型数据

len = (array) => array.length;
result = len([1, 2, 3]);

console.log(result); // 3

是什么使它们成了一等公民呢?你可以把它们当成数据到处传递,可以把它们储存在变量或者数组里面,可以用它们作为计算的输入,可以用它们做任何数据可以做的事情。

在JavaScript世界中函数却是一等公民,它不仅可以像大部分语言一样,进行声明(define)和调用(call),而且就像上述的物种类型一样,可以赋值、传参、返回。

函数也可以作为数据

函数作为参数

isEven = (num) => num % 2 === 0;
result = [1, 2, 3, 4].filter(isEven);

console.log(result); // [2, 4]

上面数组的filter方法就是用isEven函数来决定哪些数字保留,哪些被过滤掉。isEven是一个函数,同时也是另一个函数的参数。filter方法为数组的每一个成员都调用了一次isEven,并且通过isEven的返回值是true还是false来决定该成员是保留还是遗弃。

返回一个函数

multiply = (x) => (y) => x * y;

multiply一共需要两个参数,但并不是同时需要的,它先接收一个x参数,然后返回一个新的函数,新的函数只需要参数y。 因为在js的世界里,函数是一等公民,js允许函数像string、number、boolean一样作为返回值。 PS:你仍然可以通过一个双重调用来同时传递x和y两个参数。

result = multiply(10)(20);
console.log(result); // 200

先x后y

multiply10 = multiply(10);
result = multiply10(20);

console.log(result); // 200

我们从头来看上面这个例子,multiply(10)的结果储存在了变量multiply10里面,multiply10是一个以y为参数的函数,一旦传递y给它,它就会立刻计算出x*y的乘积。

更强大的可重用性

高阶函数最大的优势可能就是可重用性了,一个典型的例子就是promise,它是JavaScript的异步解决方案。

var promise = new Promise(function (resolve, reject) {
  // ...

  if (/* 异步操作成功 */){
    resolve(value);
  } else { /* 异步操作失败 */
    reject(new Error());
  }
});

我们传递一个函数作为promise构造函数的参数,来定制化对不同的异步业务场景进行处理。可以这么说,如果没有高阶函数的话,promise也将不复存在。 值得一提的是,promise的参数也是一个高阶函数,它接收两个参数resolvereject,这两个参数也都是函数,它们已经由JavaScript实现并提供给开发者了。

总结

  • 在主流编程语言中string、number、object、array都是作为一等公民存在的。
  • 在JavaScript中函数也是一等公民
  • 因此函数拥有所有一等公民的权利,可以作为函数的参数、作为函数的返回值。由此产生了高阶函数
  • 高阶函数帮助我们简化了工作,提高了代码的重用性