在計算機科學中,柯里化(Currying)是一種技術(技巧),可以把原本接受 n 個參數的函數A,轉換成只接收一個參數的函數B(B中的惟一參數,就是A的多個參數中的 第一個 參數)。面試
而後新函數B返回的,仍是一個函數,記爲C(注意原A中返回的不必定是啥)。這個C函數又只能接收一個參數(即爲A函數的 第二個 參數)......依次不斷往復,直到返回一個接收A的第 n 個參數的函數F,F中判斷這是最後一個函數了,執行,而後返回最終的值。數組
很繞口,看個例子:瀏覽器
// 咱們想要實現一個把參數相加,返回和的函數
function adder(a, b) {
return a + b;
}
adder(4,6);
// 結果爲:10
複製代碼
固然也能夠這樣寫(非柯里化)bash
function adder() {
var sum = 0;
for(var i=0;i<arguments.length;i++)
sum += arguments[i];
return sum;
}
adder(4,6);
// 10
複製代碼
用柯里化實現閉包
var adder = function(num) {
var n = num; // 對應的爲參數4
return function(y) {
return n + y; // y爲6 返回 4+6
}
}
adder(4)(6) // 10
複製代碼
從上面能夠看到,原本adder是傳2個參數adder(4, 6),柯里化的方式後,就成爲了adder(4)(6),即每次接受一個參數並放回一個函數,而後鏈式的執行。。。app
能夠看到,adder函數中有着內部函數,內部函數一直引用着n,這就造成了一個閉包,因此柯里化是閉包的應用之一,面試時直接能夠答~~~函數
從上面能夠大概瞭解了,柯里化就是,post
把原來的函數 adder(3,5,6,7,8,9) ==> adder(3)(5)(6)(7)(8)(9)()ui
注意:最後一次調用沒有參數(),因此adder中能夠經過判斷是否有參數,去判斷我是要繼續相加,仍是返回求和值了this
或是這樣也能夠
adder(3)
adder(5,6,7)
adder(8,9)
adder() // 無參數時返回和
複製代碼
那麼這麼作的好處是什麼呢?
因此咱們能夠在寫一個函數的時候,用柯里化的思想去寫;可是咱們也能夠對任何一個原有的函數,將他柯里化了,變成柯里化的思想與形式,看思路~
例:
一個原有的函數
// 不知道這test函數是啥功能,不用管他是幹啥的,但很顯然不是簡單的求和,
// 因此你不能繼續用 循環 arguments 了。。。
function test(name, id, num, score, height) {
}
複製代碼
將他柯里化,就是要將他
test("chen", 45, 789, 284.2, 178) ==> test2("chen")(45)(789)(284.2)(178)()
其中test2就是通過柯里化包裝後的test
包裝的思想是
通用封裝代碼以下,必定要搞懂!
若是仍是沒以爲有啥用,看兩個實際的例子
1. 瀏覽器事件
還記得事件要區分IE和非IE不了
var addEvent = function(el, type, fn, capture) {
if(window.addEventListener) {
el.addEventListener(type, function(e) {
fn.call(el, e)
}, capture)
} else {
el.attachEvent('on'+type, function(e) {
fn.call(el, e)
})
}
}
複製代碼
也就是說,咱們會調用addEvent,可是每次的話都得執行內部的if...else....
因此能夠用柯里化,改爲
var curEvent = (function() {
if(window.addEventListener) {
return function(el, sType, fn, capture) { // return funtion
el.addEventListener(sType, function() {
fn.call(el, e)
}, capture)
}
} else {
return function(el, sType, fn) {
el.attachEvent('on'+sType, function(e) {
fn.call(el, e)
})
}
}
})
var addEvent = curEvent(); // addEvent 這回獲得的,就是if..else...裏面的那個return 的function,因此只須要curEvent()執行一遍判斷了if..else,其餘時候就都不須要判斷了
addEvent(elem)
複製代碼
2. 函數的bind
咱們總會看到,函數能夠這樣 test.bind(this),其中bind函數就是柯里化的思想
Funtion.prototype.bind()
var foo = {
x: 888
}
var bar = function(e) {
console.log(this.x, e)
}
Function.prototype.testBind = function(scope) {
var fn = this; // 指向的 bar
return function() {
return fn.apply(scope, [].slice.call(arguments))
}
}
var test = bar.testBind(foo) // 綁定 foo ,延遲執行
console.log(test)
test(2323) // 執行, 結果是 888 2323
複製代碼
將傳入的第一個參數(foo),看成以後函數的執行上下文,,,其餘參數 再傳給 調用的方法(函數自己不執行,只進行了bind綁定,之後函數執行的時候,至關於了 延遲執行) , 因此至關於,預先綁定了對象並返回了函數,以後再執行函數,符合柯里化。
3.Redux中的 applyMiddle 中間件原理
let store = applyMiddleware(middleware1,middleware2)(createStore)(rootReducer);
export default function createLogger({ getState }) {
return (next) => // return function
(action) => {
const console = window.console;
const prevState = getState();
const returnValue = next(action);
const nextState = getState();
const actionType = String(action.type);
const message = `action ${actionType}`;
console.log(`%c prev state`, `color: #9E9E9E`, prevState);
console.log(`%c action`, `color: #03A9F4`, action);
console.log(`%c next state`, `color: #4CAF50`, nextState);
return returnValue;
};
}
複製代碼
做用總結
最後:如有錯誤之處,還請見諒,提出後會立刻修改~~~
轉載請註明出處,謝謝~~