函数柯里化

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

解释有些抽象,先来看下面的例子:

 1 //普通函数
 2 function add(num1, num2) {
 3     return num1 + num2;
 4 }
 5 
 6 //柯里化后
 7 function curriedAdd(num1) {
 8     return function(num2) {
 9         return num1 + num2;
10     }
11 }
12 
13 alert(add(2, 3);  //5
14 alert(curriedAdd(3)(5)); //8

实际上,就是把add函数的num1,num2两个参数变成了先用一个函数接收num1参数然后返回一个函数去处理num2参数。

函数柯里化的用处:

1.参数复用

 1 function check(reg, str) {
 2     return reg.test(str);
 3 }
 4 
 5 check(/d+/g, 'test');   //false
 6 check(/[a-z]+/g, 'test'); //true
 7 
 8 function curryingCheck(reg) {
 9     return function(str) {
10         return reg.test(str);
11     }
12 }
13 
14 var hasNumber = curryingCheck(/d+/g);
15 
16 hasNumber('test1');   //true
17 hasNumber('testtest');  // false
18 hasNumber('abc');  //false

 上面的示例,就是对check()函数第一个参数reg进行了复用。

2.提前确认

 1 var addEvent = function(element, event, handler) {
 2     if(document.addEventListener) {
 3         if(element && event && handler) {
 4             element.addEventListener(event, handler, false);
 5         }
 6     } else {
 7         if(element && event && handler) {
 8             element.attachEvent('on' + event, handler);
 9         }
10     }
11 }
12 
13 
14 var addEvent = (function() {
15     if(document.addEventListener) {
16         return function(element, event, handler) {
17             if(element && event && handler) {
18                 element.addEventListener(event, handler, false);
19             }
20         };
21     } else {
22         return function(element, event, handler) {
23             if(element && event && handler) {
24                 element.attachEvent('on' + event, handler);
25             }
26         };
27     }
28 })();

调用函数执行一次判断后返回一个函数,之后同一个用户就不用再进行判断了。

3.延迟运行

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

我们在JavaScript中经常使用的bind()方法,实现的机制就是currying。

柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。下面是创建柯里化函数的通用方式:

1 function curry(fn) {
2     var args = Array.prototype.slice.call(arguments, 1);
3     
4     return function() {
5         var innerArgs = Array.prototype.slice.call(arguments);
6         var finalArgs = args.concat(innerArgs);
7         return fn.apply(null, finalArgs);
8     }
9 }

 实现一个curry()函数, 将普通函数柯里化

 1 function curry(fn, args=[]) {
 2     return function() {
 3         let rest = [...args, ...arguments];
 4         if(rest.length < fn.length) {
 5             return curry.call(this, fn, rest);
 6         } else {
 7             return fn.apply(this, rest);
 8         }
 9     }
10 }
11 
12 function add(x, y, z) {
13     return a + b + c;
14 }
15 
16 let sum = curry(add);
17 console.log(sum(1)(2)(3));   //6
18 console.log(sum(1)(2, 3));   //6

函数柯里化的性能问题:

  1. 存取arguments对象通常要比存取命名参数要慢一点
  2. 一些老版本的浏览器在arguments.length的实现上是相当慢的
  3. 使用fn.apply()和fn.call()通常比直接调用fn()稍微慢点
  4. 创建大量嵌套作用域和闭包函数会带来开销,无论是在内存上还是速度上。

一道经典面试题

 1 //实现一个add方法,使计算结果能够满足如下预期:
 2 
 3 add(1)(2)(3) = 6;
 4 add(1, 2, 3)(4) = 10;
 5 add(1)(2)(3)(4)(5) = 15;
 6 
 7 function add() {
 8     var _args = Array.prototype.slice.call(arguments);
 9 
10     var _adder = function() {
11         _args.push(...arguments);
12         return  _adder;
13     };
14     
15     _adder.toString = function() {
16         return _args.reduce(function(a, b) {
17             return a + b;
18         });
19     }
20     return _adder;
21 }
22 
23 add(1)(2)(3)    //6
24 add(1, 2, 3)(4)  //10
25 add(1)(2)(3)(4)(5)   //15
26 add(2, 6)(1)  //9

参考链接:详解JS函数柯里化

 

 

原文地址:https://www.cnblogs.com/sparkler/p/13719122.html