记录柯里化函数实现的学习过程: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