定義
高階函數是至少滿足下面一個條件的函數:
1、接收一個或多個函數作為參數。比如filter函數
2、返回一個函數。 比如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})。當然我們也可以通過高階函數來自己實現:
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)這種形象。柯里化常見的應用有:參數複用、延遲計算。比如我們有個拼接接口地址的函數:
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中的參數:
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}'))
我們可以利用這種嵌套的寫法來實現,但如果嵌套過多,代碼可讀性就不是很好了。當然我們也可以在一個函數裏分過程實現,不過這樣函數就不符合單一原則了。利用函數組合我們可以這樣寫:
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的概念。