函数柯里化 (就是递归)
在函数式编程中,函数是一等公民。那么函数柯里化是怎样的呢?
函数柯里化指的是将能够接收多个参数的函数转化为接收单一参数的函数,并且返回接收余下参数且返回结果的新函数的技术。
函数柯里化的主要作用和特点就是参数复用、提前返回和延迟执行。
例如:封装兼容现代浏览器和 IE 浏览器的事件监听的方法,正常情况下封装是这样的。
1 2 3 4 5 6 7 8 9 10 11
| 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 的兼容性判断。事实上在代码中只需要执行一次兼容性判断就可以了,后续的事件监听就不需要再去判断兼容性了。那么怎么用函数柯里化优化这个封装函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var addEvent = (function() { if(window.addEventListener) { return function(el, type, fn, capture) { el.addEventListener(type, function(e) { fn.call(el, e); }, capture); } }else { return function(ele, type, fn) { el.attachEvent('on' + type, function(e) { fn.call(el, e); }) } } })()
|
js 引擎在执行该段代码的时候就会进行兼容性判断,并且返回需要使用的事件监听封装函数。这里使用了函数柯里化的两个特点:提前返回和延迟执行。
柯里化另一个典型的应用场景就是 bind 函数的实现。使用了函数柯里化的两个特点:参数复用和提前返回。
1 2 3 4 5 6 7 8 9
| Function.prototype.bind = function(){ var fn = this; var args = Array.prototye.slice.call(arguments); var context = args.shift();
return function(){ return fn.apply(context, args.concat(Array.prototype.slice.call(arguments))); }; };
|
题目
实现一个add方法,满足以下功能
add(1);//1
add(1)(2);//3
add(1,2);//3
add(1)(2)(3);//6
add(1,2)(3);//6
add(1,2,3);//6
其符合返回方法传入的所有参数的总和
add(a,b,c)(d)(e)(f,g)(h) // result=a+b+c+d+e+f+g+h
答案1(来自b站某老师的视频讲解)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function curring(fn,length) { length = length || fn.length return function (...args) { if (args.length >= length){ return fn(...args) } return curring(fn.bind(null,...args),length-args.length) } } function add() { var sum = 0 for (let i = 0; i < arguments.length; i++) { sum+=arguments[i] } return sum } add=curring(add,6) console.log(add(1,2,3)(4)(5)(6))
|
答案2
1 2 3 4 5 6 7 8 9
| var sum = 0 function add()
return add } add(1,2,3)(4)(5)(6) console.log(sum)
|
参考文章
从一道面试题认识函数柯里化