記錄柯里化函數實現的學習過程:javascript
柯里化一般也稱部分求值,其含義是給函數分步傳遞參數,每次傳遞參數後部分應用參數,並返回一個更具體的函數接受剩下的參數,這中間可嵌套多層這樣的接受部分參數函數,直至返回最後結果。html
若是要實現下面這個方法:java
add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133
上面這個函數當參數爲空的時候執行了內部參數全部值的相加,因此咱們應該考慮當參數不爲空的時候將緩存起來,在爲空的時候再相加,這樣的思路會用閉包的方式來實現。下面是實現方法:緩存
function add () { // 用來緩存全部的arguments值 let args = [].slice.call(arguments); // 新建currying函數實現柯里化 let currying = function () { // 若是參數爲空,那麼遞歸中止,返回執行結果 if (arguments.length === 0) { return args.reduce((a, b) => a + b); } else { // 不然將參數保存到args裏面,返回currying方法 args.push(...arguments); return currying } } return currying }
add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133
上面有須要注意的一點,由於currying函數裏面使用arguments,因此currying不能使用箭頭函數,箭頭函數內部的arguments的用法與箭頭函數內部的this差很少,它取的是上一級函數的arguments值。若是想用箭頭函數,currying函數能夠這樣改動:閉包
let currying = (...rest) => { // 若是參數爲空,那麼遞歸中止,返回執行結果 if (rest.length === 0) { return args.reduce((a, b) => a + b); } else { // 不然將參數保存到args裏面,返回currying方法 args.push(...rest); return currying } }
咱們返回的currying函數還能夠使用callee來實現,原理相同,可是嚴格模式下不能使用:app
function add () { // 用來緩存全部的arguments值 let args = [].slice.call(arguments); // 新建currying函數實現柯里化 return function () { // 若是參數爲空,那麼遞歸中止,返回執行結果 if (arguments.length === 0) { return args.reduce((a, b) => a + b); } else { // 不然將參數保存到args裏面,返回currying方法 args.push(...arguments); return arguments.callee } } } add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133
對普通函數進行柯里化:dom
// 柯里化函數的構造方法 function curry (fn) { // 緩存除第一個參數的全部參數 let args = [].slice.call(arguments, 1); let _fn = function () { if (arguments.length === 0) { return fn.apply(this, args) } else { args.push(...arguments); return _fn } } return _fn } function add () { return [].reduce.call(arguments, (a, b) => a + b) } console.log(curry(add, 2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)()) // 133
舉例柯里化函數思想實現的場景:函數
如減小重複傳遞的參數學習
function simpleURL(protocol, domain, path) { return protocol + "://" + domain + "/" + path; }
咱們使用的時候將會這樣:this
var myurl = simpleURL('http', 'mysite', 'home.html'); var myurl2 = simpleURL('http', 'mysite', 'aboutme.html');
咱們能夠用柯里化的思想改寫:
function curry (fn) { // 緩存除第一個參數的全部參數 let args = [].slice.call(arguments, 1); return function () {return fn.apply(this, args.concat(...arguments)) } } // 避免每次調用重複傳參 let myURL1 = curry(simpleURL, 'https', 'mysite'); let res1 = myURL1('home.html'); // console.log(res1);//https://mysite/home.html let myURL2 = curry(simpleURL, 'http', 'mysite'); let res2 = myURL2('aboutme.html'); // console.log(res2);//http://mysite/aboutme.html