0%

函数柯里化

柯里化:把接受多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,并且返回接收余下的参数而且返回结果的新函数的技术

柯里化的通用实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
const curry=(fn,...args)=>{
return args.length<fn.length//函数参数个数可以通过函数.length属性访问,
?(..._args)=>curry(fn,...args,..._args)//传入参数小于原始函数fn参数的个数时,继续对当前函数进行柯里化,返回一个接受所有参数(当前参数和剩余参数)的函数
:fn(...args)//否则直接执行函数
}
function add1(a,b,c,d){
return a+b+c+d;
}
var add=curry(add1)
console.log(add(1,2,3,4))//10
console.log(add(1)(2)(3)(4));//10
console.log(add(1,2)(3,4));//10

柯里化的作用:

参数复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 正常正则验证字符串 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

第一个参数reg进行了复用

提前返回

举个例子,兼容现代浏览器以及IE浏览器的事件添加方法,我们正常情况可能这样写:

1
2
3
4
5
6
7
8
9
10
11
12
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为元素添加事件的时候,都会走一遍if…else if…,其实只要判断一次,用柯里化

1
2
3
4
5
6
7
8
9
10
11
12
var addEvent=(function(){
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);
})
}
})();

延迟执行

比如bind方法的实现机制就是柯里化:

1
2
3
4
5
6
7
Function.prototype.bind=function(context){
var self=this;
var args=Array.prototype.slice.call(arguments,1);
return funtion(){
return self.apply(context,args);
}
}

参考文章:

https://juejin.cn/post/6844904093467541517

https://www.zhangxinxu.com/wordpress/2013/02/js-currying/

https://www.jianshu.com/p/2975c25e4d71