「前端开发」 -

JS-Currying

JavaScript —— 柯里化

Posted by eliochiu on November 16, 2022

柯里化

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 正常的函数
function add(x, y) {
  return x + y;
}

add(1, 2); // 3

// 柯里化函数
function curryingAdd(x) {
  return function(y) {
    return x + y;
  }
}

add(1)(2);

柯里化函数的作用

参数复用

1
2
3
4
5
6
7
8
function curryCheck(reg) {
  return function(txt) {
    return reg.test(txt);
  }
}

const hasDigit = curryCheck(/\d+/g);
const hasLetter = curryCheck(/[a-z]+/g);

延迟执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function add(...args) {
	return args.reduce((prev, current) => prev + current);
}

add(1, 2, 3, 4);

function curry(fn){
  let args = [];
  return function cb() {
    if(arguments.length < 1) {
    	return fn(...args);
    }
    else {
      args = [...args,...arguments]
      return cb;
    }
  }
}

cAdd = curry(add);

cAdd(1)(2)(3)(4)();

延迟执行实际上就是当我们调用这个方法时,不会立即执行,或者说在参数符合规定的时候才会执行我们真正想执行的内容。

实现方式

普通实现

1
2
3
4
5
6
7
8
9
10
11
12
function currying(fn, ...rest) {
  return function(...args) {
    return fn(...rest, ...args)
  }
}

function add(a, b, c, d) {
  return a + b + c + d;
}

const curryingAdd = currying(add, 1, 2);
curryingAdd(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
24
25
26
27
28
29
30
function currying(fn) {
  const len = fn.length; // fn参数总长度
  let _args = [];
  const curry() => {
    return function(...args) {
      // 参数攒够就执行
      if (_args.length + args.length >= len) {
        const result = fn(..._args, ...args);
        // 重置
        _args = [];
        return result;
      }
      // 否则就添加参数
      else {
        _args = [..._args, ...arg];
        return curry();
      }
    }
  }
  return curry();
}

function add(a, b, c, d) {
  return a + b + c + d;
}

const curryingAdd = currying(add);
curryingAdd(1)(2)(3)(4); // 10
curryingAdd(1, 2)(3, 4); // 10
curryingAdd(1, 2, 3)(4); // 10

经典面试题

实现一个add方法,使计算结果能够满足如下预期: add(1)(2)(3) == 6 // true add(1, 2, 3)(4) == 10 // true add(1)(2)(3)(4)(5) == 15 // true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function add() {
  // 第一次执行时,定义一个数组专门用来存储所有的参数
  var _args = Array.prototype.slice.call(arguments);

  // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
  var _adder = function() {
    _args.push(...arguments);
    return _adder;
  };

  // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
  _adder.toString = function () {
    return _args.reduce(function (a, b) {
    	return a + b;
    });
  }
  return _adder;
}