深入学习JavaScript 高阶函数
高阶函数
高阶函数英文叫Higher-orderfunction,它的定义很简单,就是至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入
- 输出一个函数
也就是说高阶函数是对其他函数进行操作的函数,可以将它们作为参数传递,或者是返回它们。简单来说,高阶函数是一个接收函数作为参数传递或者将函数作为返回值输出的函数。
函数作为参数传递
JavaScript语言中内置了一些高阶函数,比如Array.prototype.map,Array.prototype.filter和Array.prototype.reduce,它们接受一个函数作为参数,并应用这个函数到列表的每一个元素。我们来看看使用它们与不使用高阶函数的方案对比。
Array.prototype.map
map()方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果,原始数组不会改变。传递给map的回调函数(callback)接受三个参数,分别是currentValue、index(可选)、array(可选),除了callback之外还可以接受this值(可选),用于执行callback函数时使用的this值。
来个简单的例子方便理解,现在有一个数组[1,2,3,4],我们想要生成一个新数组,其每个元素皆是之前数组的两倍,那么我们有下面两种使用高阶和不使用高阶函数的方式来实现。
不使用高阶函数
//木易杨 constarr1=[1,2,3,4]; constarr2=[]; for(leti=0;i使用高阶函数
//木易杨 constarr1=[1,2,3,4]; constarr2=arr1.map(item=>item*2); console.log(arr2); //[2,4,6,8] console.log(arr1); //[1,2,3,4]Array.prototype.filter
filter()方法创建一个新数组,其包含通过提供函数实现的测试的所有元素,原始数组不会改变。接收的参数和map是一样的,其返回值是一个新数组、由通过测试的所有元素组成,如果没有任何数组元素通过测试,则返回空数组。
来个例子介绍下,现在有一个数组[1,2,1,2,3,5,4,5,3,4,4,4,4],我们想要生成一个新数组,这个数组要求没有重复的内容,即为去重。
不使用高阶函数
constarr1=[1,2,1,2,3,5,4,5,3,4,4,4,4]; constarr2=[]; for(leti=0;i使用高阶函数
constarr1=[1,2,1,2,3,5,4,5,3,4,4,4,4]; constarr2=arr1.filter((element,index,self)=>{ returnself.indexOf(element)===index; }); console.log(arr2); //[1,2,3,5,4] console.log(arr1); //[1,2,1,2,3,5,4,5,3,4,4,4,4]Array.prototype.reduce
reduce()方法对数组中的每个元素执行一个提供的reducer函数(升序执行),将其结果汇总为单个返回值。传递给reduce的回调函数(callback)接受四个参数,分别是累加器accumulator、currentValue、currentIndex(可选)、array(可选),除了callback之外还可以接受初始值initialValue值(可选)。
- 如果没有提供initialValue,那么第一次调用callback函数时,accumulator使用原数组中的第一个元素,currentValue即是数组中的第二个元素。在没有初始值的空数组上调用reduce将报错。
- 如果提供了initialValue,那么将作为第一次调用callback函数时的第一个参数的值,即accumulator,currentValue使用原数组中的第一个元素。
来个简单的例子介绍下,现在有一个数组[0,1,2,3,4],需要计算数组元素的和,需求比较简单,来看下代码实现。
不使用高阶函数
constarr=[0,1,2,3,4]; letsum=0; for(leti=0;i//10
console.log(arr);
//[0,1,2,3,4]使用高阶函数
无initialValue值
constarr=[0,1,2,3,4]; letsum=arr.reduce((accumulator,currentValue,currentIndex,array)=>{ returnaccumulator+currentValue; }); console.log(sum); //10 console.log(arr); //[0,1,2,3,4]上面是没有initialValue的情况,代码的执行过程如下,callback总共调用四次。
callback accumulator currentValue currentIndex array returnvalue firstcall 0 1 1 [0,1,2,3,4] 1 secondcall 1 2 2 [0,1,2,3,4] 3 thirdcall 3 3 3 [0,1,2,3,4] 6 fourthcall 6 4 4 [0,1,2,3,4] 10 有initialValue值
我们再来看下有initialValue的情况,假设initialValue值为10,我们看下代码。
constarr=[0,1,2,3,4]; letsum=arr.reduce((accumulator,currentValue,currentIndex,array)=>{ returnaccumulator+currentValue; },10); console.log(sum); //20 console.log(arr); //[0,1,2,3,4]代码的执行过程如下所示,callback总共调用五次。
callback accumulator currentValue currentIndex array returnvalue firstcall 10 0 0 [0,1,2,3,4] 10 secondcall 10 1 1 [0,1,2,3,4] 11 thirdcall 11 2 2 [0,1,2,3,4] 13 fourthcall 13 3 3 [0,1,2,3,4] 16 fifthcall 16 4 4 [0,1,2,3,4] 20 函数作为返回值输出
这个很好理解,就是返回一个函数,下面直接看两个例子来加深理解。
isType函数
我们知道在判断类型的时候可以通过Object.prototype.toString.call来获取对应对象返回的字符串,比如:
letisString=obj=>Object.prototype.toString.call(obj)==='[objectString]'; letisArray=obj=>Object.prototype.toString.call(obj)==='[objectArray]'; letisNumber=obj=>Object.prototype.toString.call(obj)==='[objectNumber]';可以发现上面三行代码有很多重复代码,只需要把具体的类型抽离出来就可以封装成一个判断类型的方法了,代码如下。
letisType=type=>obj=>{ returnObject.prototype.toString.call(obj)==='[object'+type+']'; } isType('String')('123');//true isType('Array')([1,2,3]);//true isType('Number')(123);//true这里就是一个高阶函数,因为isType函数将obj=>{...}这一函数作为返回值输出。
add函数
我们看一个常见的面试题,用JS实现一个无限累加的函数add,示例如下:
add(1);//1 add(1)(2);//3 add(1)(2)(3);//6 add(1)(2)(3)(4);//10 //以此类推我们可以看到结构和上面代码有些类似,都是将函数作为返回值输出,然后接收新的参数并进行计算。
我们知道打印函数时会自动调用toString()方法,函数add(a)返回一个闭包sum(b),函数sum()中累加计算a=a+b,只需要重写sum.toString()方法返回变量a就可以了。
functionadd(a){ functionsum(b){//使用闭包 a=a+b;//累加 returnsum; } sum.toString=function(){//重写toString()方法 returna; } returnsum;//返回一个函数 } add(1);//1 add(1)(2);//3 add(1)(2)(3);//6 add(1)(2)(3)(4);//10以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。