Currying

把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
  • 优缺点
  1. 参数复用
  2. 提前确定执行函数
  3. 延迟计算,惰性求值
  • 性能

存取 arguments 对象通常比存取命名参数慢
老版本浏览器 arguments.length 实现上相当慢
fn.apply()、fn.call() 比直接调用 fn()慢
大量嵌套作用域和闭包性能损耗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function curry (fn, currArgs) {
return function() {
let args = [].slice.call(arguments);
// 首次调用时,若未提供最后一个参数currArgs,则不用进行args的拼接
if (currArgs !== undefined) {
args = args.concat(currArgs);
}
// 递归调用
if (args.length < fn.length) {
return curry(fn, args);
}
// 递归出口
return fn.apply(null, args);
}
}

Array.prototype.slice.call(arguments)

把 arguments 转化成数组

反柯里化

一个泛型化的过程。它使得被反柯里化的函数,可以接收更多参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Toast(option){
this.prompt = '';
}
Toast.prototype = {
constructor: Toast,
// 输出提示
show: function(){
console.log(this.prompt);
}
};

// 新对象
var obj = {
prompt: '新对象'
};

function unCurrying(fn){
return function(){
var args = [].slice.call(arguments);
var that = args.shift();
return fn.apply(that, args);
}
}

var objShow = unCurrying(Toast.prototype.show);

objShow(obj);

实现方式

1
2
3
4
5
6
7
8
9
Function.prototype.unCurrying = function(){
var self = this;
return function(){
return Function.prototype.call.apply(self, arguments);
}
}

var objShow = Toast.prototype.show.unCurrying();
objShow(obj);

事件监听 柯里化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function nodeListen(node, eventName){
return function(fn){
node.addEventListener(eventName, function(){
fn.apply(this, Array.prototype.slice.call(arguments));
}, false);
}
}

var bodyClickListen = nodeListen(document.body, 'click');
bodyClickListen(function(){
console.log('first listen');
});

bodyClickListen(function(){
console.log('second listen');
});

部分应用

部分应用函数是将一个函数转化为具有更少的元素(即更少的参数)的函数。