简介

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

>

示例

  1. // 普通的add函数
  2. function add(x, y) {
  3. return x + y
  4. }
  5. // currying后
  6. function curryingAdd(x) {
  7. return function (y) {
  8. return x + y
  9. }
  10. }
  11. curryingAdd(1)(2) // 3

作用

1. 参数复用

  1. function curryingCheck(reg) {
  2. return function(txt) {
  3. return reg.test(txt)
  4. }
  5. }
  6. var hasDigit = curryingCheck(/\d+/g)
  7. var hasLetter = curryingCheck(/[a-z]+/g)
  8. hasDigit('test1') // true
  9. hasDigit('test') // false
  10. hasLetter('123') // false

2. 提前确认

  1. const on = (document, element, event, handler) => {
  2. if (document.addEventListener) {
  3. element.addEventListener(event, handler, false);
  4. }
  5. else {
  6. element.attachEvent('on' + event, handler);
  7. }
  8. };
  9. // 提前确认注册事件的方法,就不用在每次调用on时候确认
  10. const on = (doc => {
  11. return doc.addEventListener
  12. ? (element, event, handler) => {
  13. element.addEventListener(event, handler, false);
  14. }
  15. : (element, event, handler) => {
  16. element.attachEvent('on' + event, handler);
  17. }
  18. })(document);

3. 延迟运行

  1. function add(...args) {
  2. return args.reduce((prev, current) => prev + current);
  3. }
  4. add(1, 2, 3, 4);
  5. function curry(fn){
  6. let args = [];
  7. return function cb() {
  8. if(arguments.length < 1) {
  9. return fn(...args);
  10. }
  11. else {
  12. args = [...args,...arguments]
  13. return cb;
  14. }
  15. }
  16. }
  17. cAdd = curry(add);
  18. cAdd(1)(2)(3)(4)();

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

实现

1. 通用实现

  1. function currying(fn, ...rest) {
  2. return function(...args) {
  3. return fn(...rest, ...args);
  4. }
  5. }
  6. function sum(a, b, c, d) {
  7. console.log(a + b + c + d)
  8. }
  9. const add = currying(sum, 1, 2);
  10. add(3, 4);
  11. // 执行结果
  12. 10

2. 递归实现

  1. function add(a, b, c, d) {
  2. console.log(a + b + c + d);
  3. }
  4. const curriedAdd = currying(add);
  5. curriedAdd(1)(2)(3)(4); // 10
  6. curriedAdd(1, 2, 3)(4); // 10
  7. curriedAdd(1, 2, 3, 4); // 10
  8. function currying(fn) {
  9. const len = fn.length;
  10. let _args = [];
  11. const curry = () => {
  12. return function (...args) {
  13. // 如果参数攒够了就执行
  14. if (_args.length + args.length >= len) {
  15. const result = fn(..._args, ...args);
  16. // 执行完重置_args
  17. _args = [];
  18. return result;
  19. }
  20. // 参数不够就继续攒
  21. else {
  22. _args = [..._args, ...args];
  23. return curry();
  24. }
  25. }
  26. }
  27. return curry();
  28. }

经典面试题

  1. // 实现一个add方法,使计算结果能够满足如下预期:
  2. // add(1)(2)(3) == 6 // true
  3. // add(1, 2, 3)(4) == 10 // true
  4. // add(1)(2)(3)(4)(5) == 15 // true
  5. function add() {
  6. // 第一次执行时,定义一个数组专门用来存储所有的参数
  7. var _args = Array.prototype.slice.call(arguments);
  8. // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
  9. var _adder = function() {
  10. _args.push(...arguments);
  11. return _adder;
  12. };
  13. // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
  14. _adder.toString = function () {
  15. return _args.reduce(function (a, b) {
  16. return a + b;
  17. });
  18. }
  19. return _adder;
  20. }