我们都知道函数是被设计为执行特定任务的代码块,会在某代码调用它时被执行,获得返回值或者实现其他功能。函数有函数名和参数,而函数参数是当调用函数接收的真实的值。
今天要说的高阶函数的英文为Higher-order function
, 高阶函数的高阶是什么意思呢?
定义
至少满足下列一个条件的函数
- 接收一个或多个函数作为输入
- 输出一个函数
怎么理解这么个东西呢?引言里说过了,函数实际上都是指向某个变量。既然变量可以是一个向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
//一个简单的高阶函数 function add(x,y,f){ return f(x)+f(y); } var x=add(-5,6,Math.abs); //-> 11
一些常见的高阶函数
JS中设置了一些高阶函数,比如Array.prototype.map
,Array.prototype.filter
和Array.prototype.reduce
,他们接收一个函数作为参数,并应用这个函数到列表的每一个元素。
Array.prototype.map
map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果,原始数组不会改变。
举个栗子~我们有个函数f(x)=x2,要把这个函数作用在一个数组[1, 2, 3, 4, 5, 6, 7, 8, 9]
上,就可以用map实现:
fuction pow(x){ return x*x; } var arr=[1, 2, 3, 4, 5, 6, 7, 8, 9]; var result=arr.map(pow); //[1, 4, 9, 16, 25, 36, 49, 64, 81] console.log(results);
值得注意的点:map()
传入的参数是pow
,即一个函数对象本身。
虽然不用高阶函数依靠循环也能实现上述功能,但是作为高阶函数可以计算任意复杂的函数,也体现了高阶函数的价值。
Array.prototype.reduce
reduce()
方法对数组中的每个元素执行一个提供的reducer
函数(升序执行),将其结果汇总为单个返回值。
Array
的reduce()
把一个函数作用在这个Array
的[x1, x2, x3...]
上,这个函数必须接收两个参数,reduce()
把结果继续和序列的下一个元素做累积计算,其效果就是:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
比方说对一个Array
求和,就可以用reduce
实现:
var arr=[1,3,5,7,9]; arr.reduce(function(x,y){ return x+y; }); //-> 25
Array.prototype.filter
filter()
方法创建一个新数组, 其包含通过提供函数实现的测试的所有元素,原始数组不会改变。
filter
也是一个常用的操作,它用于把Array
的某些元素过滤掉,然后返回剩下的元素。 和map()
类似,Array
的filter()
也接收一个函数。和map()
不同的是,filter()
把传入的函数依次作用于每个元素,然后根据返回值是true
还是false
决定保留还是丢弃该元素。
例如,在一个Array中,删除偶数,只保留奇数:
var arr=[1,2,3,4,5,6,7,8]; var r=arr.filter(function(x){ return (x%2 !==0); }); console.log(r); //=> [1,3,5,7]
把一个Array中的空字符删除:
var arr = [‘A‘, ‘‘, ‘B‘, null, undefined, ‘C‘, ‘ ‘]; var r = arr.filter(function (s) { return s && s.trim(); // 注意:IE9以下的版本没有trim()方法 }); r; // [‘A‘, ‘B‘, ‘C‘]
所以!filter()
实际上是一个筛选函数。
回调函数
filter()
接收的回调函数其实可以有很多个参数。通常我们仅使用第一个参数,表示Array
的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:
这里利用filter
巧妙地实现了去重(我觉得很酷)
var arr = [‘A‘, ‘B‘, ‘C‘]; var r = arr.filter(function (element, index, self) { console.log(element); // 依次打印‘A‘, ‘B‘, ‘C‘ console.log(index); // 依次打印0, 1, 2 console.log(self); // self就是变量arr return true; }); var r,arr=[‘apple‘, ‘strawberry‘, ‘banana‘, ‘pear‘, ‘apple‘, ‘orange‘, ‘orange‘, ‘strawberry‘]; r=arr.filter(function(element,index,self){ return self.indexOf(element)===index; });
除了上述的几个常用的高阶函数,还有很多比较厉害的高阶函数,包括sort()
,every()
,finf()
,findIndex()
,forEach()
等等,我会附在文章下面的参考中。
函数作为返回值输出
顾名思义,就是返回一个函数嘛,直接上例子:
我们可以用Object.prototype.toString.call
来获取对应对象返回的字符串,来判断类型
let isType = type => obj => { return Object.prototype.toString.call( obj ) === ‘[object ‘ + type + ‘]‘; } isType(‘String‘)(‘123‘); // true isType(‘Array‘)([1, 2, 3]); // true isType(‘Number‘)(123); // true
总结
高阶函数的功能很大程度上可以用普通的函数实现,但是高阶函数是代码更加抽象容易理解,使功能更加简洁,在函数复杂时可以很便捷地实现需要的功能,是个很好很好的东西~
参考: 廖雪峰-高阶函数 ; 木易杨前端进阶-高阶函数