柯里化这个词一看就感觉高大上,实际当你了解后才发现其实就是高阶函数的一个特殊用法
柯里化是什么?
柯里化 Currying ,就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
做个简单示例:
// 普通的add函数
function add(x, y) {
return x + y
}
// Currying后
function curryingAdd(x) {
return function (y) {
return x + y
}
}
add(1, 2) // 3
curryingAdd(1)(2) // 3
为什要柯里化?有什么好处和作用?
1. 参数复用
// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g, 'test') //false
check(/[a-z]+/g, 'test') //true
// Currying后
function curryingCheck(reg) {
return function(txt) {
return reg.test(txt)
}
}
var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)
hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false
上面的示例是一个正则的校验,正常来说直接调用check函数就可以了,但是如果我有很多地方都要校验是否有数字,其实就是需要将第一个参数reg进行复用,这样别的地方就能够直接调用hasNumber,hasLetter等函数,让参数能够复用,调用起来也更方便。
2.提前确认
var on = (function() {
if (document.addEventListener) {
return function(element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
};
} else {
return function(element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
};
}
})();
//换一种写法可能比较好理解一点,上面就是把isSupport这个参数给先确定下来了
var on = function(isSupport, element, event, handler) {
isSupport = isSupport || document.addEventListener;
if (isSupport) {
return element.addEventListener(event, handler, false);
} else {
return element.attachEvent('on' + event, handler);
}
我们在做项目的过程中,封装一些dom操作可以说再常见不过,上面第一种写法也是比较常见,但是我们看看第二种写法,它相对一第一种写法就是自执行然后返回一个新的函数,这样其实就是提前确定了会走哪一个方法,避免每次都进行判断。
3. 延迟运行
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function() {
return _this.apply(context, args)
}
}
像我们js中经常使用的bind,实现的机制就是Currying.
面试题:编写一个ADD函数满足如下需求
add(1); //1
add(1)(2); //3
add(1)(2)(3); //6
add(1)(2,3); //6
add(1,2)(3); //6
add(1,2,3); //6
方法一:
思路:1、参数未定,调用次数未定 2、返回结果必须是个函数
function add(...outerArgs){
// outerArgs 已经拿到了第一次执行的参数合集
// 重写 add 函数
add = function(...innerArgs){
// innerArgs 下次函数执行的参数合集
// outerArgs 和 innerArgs 合并就是每次执行函数和参数合用来求和
outerArgs = outerArgs.concat(innerArgs)
// 返回结果是一个函数
return add
}
// 重写toString 方法 为求和 在alert时就可以得到和
add.toString = function(){
return outerArgs.reduce((x,y)=> x+y)
}
// 返回结果是一个函数
return add
}
alert(add(1))
方法二:
function currying(anonymous,length){
return function add(...args){
if(args.length >= length){
return anonymous(...args)
}
return currying(anonymous.bind(null,...args),length - args.length)
}
}
let add = currying(function anonymous(...args){
return args.reduce((x,y)=>x+y)
},3)
console.log(add(1,2)(3))