高階函數是至少知足如下條件之一的函數:javascript
舉幾個例子,js中的排序函數sort,就是函數做爲參數的一個高階函數。java
// 從小到大
[1,5,8,6,9,0].sort(function(a, b){
return a - b;
})
// [0,1,5,6,8,9]
//從大到小
[1,5,8,6,9,0].sort(function(a, b){
return b - a;
})
// [9,8,6,5,1,0]
複製代碼
js中判斷數據類型的,就是函數做爲返回值。es6
const isType = function(type){
return function(obj){
return object.prototype.toString.call(obj) === `[object ${type}]`;
}
}
let isNumber = isType('Number');
console.log(isNumber(20)); // true
複製代碼
函數柯里化(function currying)概念最先是由俄國數學家Moses Schönfinkel發明出來,後由數學家Haskell Curry豐富和發展,currying由此得名。編程
currying又稱部分求值。一個currying函數首先會接收一些參數,接受了這些參數以後,該函數並不會當即求值,而是繼續返回另外一個函數,剛纔傳入的參數在函數形式的閉包中 被保存起來。待到函數真正須要求值的時候,以前傳入的因此參數都會被一次性用於求值。閉包
下面來看一個最簡單的計費函數:app
let totalCost = 0;
let billing = function(num){
totalCost += num;
};
billing(20);
billing(12);
billing(64);
billing(16);
console.log(totalCost); //112
複製代碼
經過這段代碼咱們能夠計算出某時間段的費用,然而這段代碼有兩個弊端,一是在外部暴露了一個全局變量,容易致使變量污染;二是咱們並不關心天天花費多少,並不想每次花費都計算一次,而是 但願在最後須要計算時在所有作計算。接下來咱們改進代碼,用currying實現效果。函數式編程
let totalCost = (function(){
let args = [];
return function(){
if(arguments.length === 0){
let money = 0;
for(let i = 0, l = args.length; i < l; i++){
money += args[i];
}
return money;
}else{
[].push.apply(args, arguments);
}
}
})();
totalCost(12);
totalCost(62);
totalCost(15);
console.log(const()); // 89
複製代碼
多箭頭函數其實就是函數柯里化的es6寫法,好比咱們常見的求和函數,採用高階函數的寫法:函數
function sum(a){
return function(b){
return a + b;
}
}
let addLater = sum(3);
console.log(addLater(5)); //8
複製代碼
採用es6對箭頭的寫法等價於:let sum = a => b => a + b;
ui
wiki 的柯里化定義: 把接受多個參數的函數變換成接受一個單一參數的函數,而且返回(接受餘下的參數並且返回結果的)新函數的技術spa
簡單的理解就是,把第一個參數變量存在了函數(閉包)裏面,而後須要n
個參數就變成了須要n-1
個參數就能夠調 用函數了。例如上面的案例:
let sum = a => b => a + b;
let sum2 = sum(2);
複製代碼
原本完成sum操做應該是:
let sum = (a, b) => x + y;
複製代碼
它須要倆參數,而上面的sum
函數完成一樣操做只須要一個參數,這在函數式編程中普遍應用。
詳細解釋一下,就是sum
函數等價於有了x
這個閉包變量的y => x + y
函數。
也所以當a = 2
,而後再調用sum2(5)
時:
sum(5) ==== 2 + 5
複製代碼
函數柯里化有兩個功能:一是能夠惰性求值;二是能夠提早傳遞部分參數。