高阶函数数组
知足下列条件之一的函数:闭包
函数做为参数被传递(如回调函数);app
函数能够做为返回值输出;函数
一些内置高阶函数的例子:测试
Array.prototype.mapthis
map()方法经过调用对输入数组中的每一个元素调用回调函数来建立一个新数组。spa
map()方法将获取回调函数的每一个返回值,并使用这些值建立一个新数组。prototype
map()方法的回调函数总共接收3个参数:element,index和array。rest
例子:code
假设咱们有一个数字数组,咱们想建立一个新数组,新数组的每一个值是原数组对应值的两倍。
不使用高阶函数:
const arr1 = [1, 2, 3]; const arr2 = []; for(let i = 0; i < arr1.length; i ++) { arr2.push(arr[i] * 2); } console.log(arr2); //[2, 4, 6]
使用高阶函数:
const arr1 = [1, 2, 3]; const arr2 = arr1.map(item=> item * 2); console.log(arr2);
Array.prototype.filter
filter()方法会建立一个新数组,其中包含全部经过回调函数测试的元素。传递给filter()方法的回调函数接受3个参数:element,index和array
例子:
假设咱们有一个包含数字值的数组,选择其中的数值建立一个数值大于18的数组
不使用高阶函数:
const arr1 = [1, 2, 19, 20]; const arr2 = []; for(let i = 0; i < arr1.length; i ++) { if(arr1[i] > 18) { arr2.push(arr1[1]) } } console.log(arr2)
使用高阶函数:
const arr1 = [1, 2, 19, 20]; const arr2 = arr1.filter(item=> item > 18); console.log(arr2)
Array.prototype.reduce
reduce()方法对调用数组的每一个元素执行回调函数,最后生成一个单一的值并返回。
reduce()方法接受两个参数:redecer函数(回调),一个可选的initialValue
reducer函数(回调)接受4个参数:accumulater, currentValue, currentIndex, sourceArray
若是提供了 initialValue,则累加器将等于 initialValue,currentValue 将等于数组中的第一个元素。
若是没有提供 initialValue,则累加器将等于数组中的第一个元素,currentValue 将等于数组中的第二个元素。
例子:
对一个数字数组的求和:
不使用高阶函数:
const arr = [1, 2, 7]; let sum = 0; for(let i = 0; i< arr.length; i++) { sum = sum + arr[i] }
// 10
使用高阶函数:
const arr = [1, 2, 7]; const sum = arr.reduce((accumulator,currentValue)=> return accumulator + currentValue ) // 10
还能够为它提供初始值:
const arr = [1, 2, 7]; const sum = arr.reduce((accumulator,currentValue)=> return accumulator + currentValue,10 ) // 20
柯里化
柯里化(currying)又称部分求值。一个currying的函数首先会接受一些参数,接受这些参数以后,函数并不会当即求值,而是继续返回另外一个函数,刚才传入的参数在函数造成的闭包中被保存起来。待到函数被真正须要求值的时候,以前传入的全部参数都会被一次性用于求值。
计算天天的花销
var currying = function(fn) { var args = []; return function() { if (arguments.length === 0) { return fn.apply(this, args); } else { Array.prototype.push.apply(args, arguments); return arguments.callee; } } } cost = function(){ var sum = 0; for (var i = 0, len = arguments.length; i < len; i++) { sum += arguments[i]; } return sum; } var cost = currying(cost); cost(100); cost(200); alert(cost())
通俗地讲,柯里化就是一个部分配置多参数函数的过程,每一步都返回一个接受单个参数的部分配置好的函数。一些极端的状况可能须要分不少次来部分配置一个函数,好比说屡次相加:
multiPlus(1)(2)(3); // => 6
上代码
// ES5 function curry(fn) { function _c(restNum, argsList) { return restNum === 0 ? fn.apply(null, argsList) : function(x) { return _c(restNum - 1, argsList.concat(x)); }; } return _c(fn.length, []); } // ES6 const curry = fn => { const _c = (restNum, argsList) => restNum === 0 ? fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []); } /***************** 使用 *********************/ var plus = curry(function(a, b) { return a + b;
});
分析:
咱们须要一个curry函数,它接受一个待柯里化的函数为参会素,返回一个用于接收一个参数的函数,接收到的参数放到一个列表中,当参数数量足够时,执行原函数并返回结果。
实现方式:
简单思考能够知道,柯里化部分配置函数的步骤数等于 fn 的参数个数,也就是说有两个参数的 plus 函数须要分两步来部分配置。函数的参数个数能够经过fn.length
获取。
总的想法就是每传一次参,就把该参数放入一个参数列表 argsList 中,若是已经没有要传的参数了,那么就调用fn.apply(null, argsList)
将原函数执行。要实现这点,咱们就须要一个内部的判断函数 _c(restNum, argsList),函数接受两个参数,一个是剩余参数个数 restNum,另外一个是已获取的参数的列表 argsList;_c 的功能就是判断是否还有未传入的参数,当 restNum 为零时,就是时候经过fn.apply(null, argsList)
执行原函数并返回结果了。若是还有参数须要传递的话,也就是说 restNum 不为零时,就须要返回一个单参数函数
function(x) { return _c(restNum - 1, argsList.concat(x)); }
来继续接收参数。这里造成了一个尾递归,函数接受了一个参数后,剩余须要参数数量 restNum 减一,并将新参数 x 加入 argsList 后传入 _c 进行递归调用。结果就是,当参数数量不足时,返回负责接收新参数的单参数函数,当参数够了时,就调用原函数并返回。
如今再来看:
function curry(fn) { function _c(restNum, argsList) { return restNum === 0 ? fn.apply(null, argsList) : function(x) { return _c(restNum - 1, argsList.concat(x)); }; } return _c(fn.length, []); // 递归开始 }
可使用ES6写法,用数组结构和箭头函数:
// ES6 const curry = fn => { const _c = (restNum, argsList) => restNum === 0 ? fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []); }
另一种方法:
function curry(fn) { const len = fn.length; return function judge(...args1) { return args1.length >= len ? fn(...args1): function(...args2) { return judge(...[...args1, ...args2]); } } } // 使用箭头函数 const curry = fn => { const len = fn.length; const judge = (...args1) => args1.length >= len ? fn(...args1) : (...args2) => judge(...[...args1, ...args2]); return judge; }