高階函數是至少知足下面一個條件的函數:
一、接收一個或多個函數做爲參數。好比filter
函數
二、返回一個函數。 好比bind
函數
舉個例子:好比咱們要篩數組[1,2,3,4,5]
中大於3的全部元素,咱們一般的實現方法爲:編程
let newArr = []; for(let i = 0,len = arr.length; i < len; i++){ arr[i] > 3 && newArr.push(arr[i]) }
而使用數組filter
方法的話,只須要 let newArr = arr.filter((item) => {return item > 3})
。固然咱們也能夠經過高階函數來本身實現:api
Array.prototype.myFilter = function (fn){ let newArr = []; for(let i = 0,len = this.length; i < len; i++){ fn(this[i]) && newArr.push(this[i]) } return newArr; } [1,2,3,4,5].myFilter((item) => { return item > 3})
咱們能夠經過封裝高階函數來複用和簡化咱們的代碼。數組
柯里化是將一個多參數的函數轉換成多個單參數的函數,這個函數會返回一個函數去處理下一個參數。也就是把fn(a,b,c)
轉換爲newFn(a)(b)(c)
這種形象。柯里化常見的應用有:參數複用、延遲計算。好比咱們有個拼接接口地址的函數:app
function getUrl(service,context,api){ return service + context + api; } let loginUrl = getUrl('http://localhost:8080/','auth','/login') let logoutUrl = getUrl('http://localhost:8080/','auth','/logout')
每次前兩個參數的值都是同樣,咱們能夠柯里化來封裝下來達到參數複用:函數
function curry(fn){ let args = Array.prototype.slice.call(arguments,1); return function(){ let innerArgs = Array.prototype.slice.call(arguments); let finalArgs = args.concat(innerArgs); if(finalArgs.length < fn.length){ //fn.length爲函數的參數個數 return curry.call(this,fn,...finalArgs) }else{ return fn.apply(null,finalArgs) } } } var getAuthUrl = curry(getUrl,'http://localhost:8080/','auth'); let loginUrl = getAuthUrl('/login') let logoutUrl = getAuthUrl('/logout')
組合函數相似於管道,多個函數的執行時,上一個函數的返回值會自動傳入到第二個參數繼續執行。好比咱們替換一個url中的參數:this
function replaceToken(str){ return str.replace(/{token}/g,'123455') } function replaceAccount(str){ return str.replace(/{account}/g,'xuriliang') } replaceAccount(replaceToken('http://localhost/api/login?token={token}&account={account}'))
咱們能夠利用這種嵌套的寫法來實現,但若是嵌套過多,代碼可讀性就不是很好了。固然咱們也能夠在一個函數裏分過程實現,不過這樣函數就不符合單一原則了。利用函數組合咱們能夠這樣寫:url
function compose() { var args = arguments; var start = args.length - 1; return function() { var i = start; var result = args[start].apply(this, arguments); while (i--) result = args[i].call(this, result); return result; } } compose(replaceToken,replaceAccount)('http://localhost/api/login?token={token}&account={account}')
組合函數使得咱們可使用一些通用的函數,組合出各類複雜運算。這也是函數編程中pointfree
的概念。prototype