高阶函数 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的参数也是一个高阶函数,它接收两个参数resolve和reject,这两个参数也都是函数,它们已经由JavaScript实现并提供给开发者了。
总结
- 在主流编程语言中string、number、object、array都是作为一等公民存在的。
- 在JavaScript中函数也是一等公民
- 因此函数拥有所有一等公民的权利,可以作为函数的参数、作为函数的返回值。由此产生了高阶函数
- 高阶函数帮助我们简化了工作,提高了代码的重用性