歡迎關注個人公衆號睿Talk
,獲取我最新的文章:
javascript
柯里化,是函數式編程的一個重要概念。對於沒接觸過的人來講,會被一串串的小括號弄得摸不着頭腦。但一旦理解了其中的含義和具體的使用場景,你必定會對它愛不釋手。它既能減小代碼冗餘,也能增長可讀性,可謂程序猿居家旅行,裝逼撕逼必備之良藥。java
若是一個函數能夠接收多個參數,將這個函數轉化爲每次只接收一部分參數的函數的屢次調用形式,就是柯里化。文字上理解比較困難,先來看看下面的代碼:react
function add(a, b, c) { return a + b + c; }
這個add函數接收3個參數,返回3個參數相加的結果。能夠經過如下2種形式對其進行柯里化:編程
function addOne(a) { return function(b) { return function(c) { return a + b + c; } } } } function addTwo(a,b) { return function(c) { return a + b + c; } }
執行的時候,如下3種方式都會得到同樣的結果:redux
add(1, 2, 3); // return 6 addOne(1)(2)(3); // return 6 addTwo(1, 2)(3); // return 6
若是使用ES6語法,能更簡潔的寫出柯里化後的函數,以addOne爲例:segmentfault
const addOne = (a) => (b) => (c) => (a + b + c)
上面的例子沒有什麼實際的意義,只是爲了說明概念而已。在瞭解基本概念後,咱們來聊聊實際的使用場景。數組
能夠將一些模板代碼經過柯里化的形式預先定義好,例如:瀏覽器
var addEvent = function(el, type, fn, capture) { if (window.addEventListener) { el.addEventListener(type, function(e) { fn.call(el, e); }, capture); } else if (window.attachEvent) { el.attachEvent("on" + type, function(e) { fn.call(el, e); }); } }; addEvent(element, "click", handleClick, true);
這段代碼的做用就是根據瀏覽器的類型決定事件添加的方式。實際上if...else的判斷只須要進行一次。將它柯里化後能夠獲得如下結果:性能優化
function addCrossBrowserEvent() { if (window.addEventListener) { return function(el, sType, fn, capture) { el.addEventListener(sType, function(e) { fn.call(el, e); }, (capture)); }; } else if (window.attachEvent) { return function(el, sType, fn, capture) { el.attachEvent("on" + sType, function(e) { fn.call(el, e); }); }; } } var addEvent = addCrossBrowserEvent(); addEvent(element, "click", handleClick, true);
在有回調函數的場景下,能夠經過柯里化傳入一些預設的值,排列組合後,達到代碼複用的效果:app
// 匹配任何正則的函數 const match = (reg) => (str) => str.match(reg); // 專門匹配空格 const hasSpace = match(/\s+/g); // 封裝數組的 filter 方法 const filter = (fn) => (arr) => arr.filter(fn); // 專門找空格的 filter 方法 const findSpace = filter(hasSpace); // 使用 let result = findSpace(['hi man', 'hi_man']); //['hi man']
使用傳統的方法實現以上效果,以下:
let result = ['hi man', 'hi_man'].filter( (item) => (item.match(/\s+/g)) );
雖然傳統的方法看起來代碼量比較少,但若是在不少地方須要使用的時候,就體現出封裝的威力了。並且,還能夠爲filter方法傳入其它的條件生成各式各樣的find工具函數!
react-redux的connect方法,就是使用了柯里化增長代碼的可讀性:
let Container = connect(mapStateToProps, mapDispatchToProps)(Component);
在這裏,connect的做用就是將Component要用到的state切面和action注入到它的property中,達到展現型組件和容器組件分離的目的。若是將這個方法的定義改成:
let Container = connect(mapStateToProps, mapDispatchToProps, Component);
就沒那麼好理解了。並且,mapStateToProps和mapDispatchToProps實際上也是可選參數,在不傳它們的狀況下傳入Component會顯得很噁心: connect(null, null, Component)。
ES5中的bind方法,就是經過柯里化實現的:
if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; if (this.prototype) { fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; }
經過本文的介紹,相信你對柯里化已經有一個全新的認識了。它最少有如下4種功能:
靈活使用柯里化,提升代碼質量不是夢!
P.S. 若是還有本文沒有提到的柯里化用法,歡迎留言交流(^-^)