美文网首页
函数柯里化

函数柯里化

作者: puxiaotaoc | 来源:发表于2022-07-06 08:24 被阅读0次
    一、纯函数

    在程序设计中,若一个函数符合以下条件,则这个函数为纯函数:
    1、确定的输入,一定会产出确定的输出
    2、函数在执行过程中,不能产生副作用

    副作用:执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储,副作用往往是产生bug的温床

    let name = 'a';
    function foo() {
      console.log(name);
    }
    foo(); // a
    name = 'b';
    foo(); // b
    
    // slice函数是纯函数
    // splice是非纯函数:执行时有修改原来的数组本身
    
    function baz(info) { // 非纯函数
      info.age = 18;
    }
    
    const obj = {
      name: '小红',
      age: 10,
    };
    
    baz(obj);
    console.log(obj); // {name: '小红', age: 18}
    
    二、函数柯里化

    只传递给函数一部分的参数来调用它,让它返回一个函数去处理剩余的参数,这个过程就称之为柯里化

    // 原函数
    function add(m, n, x, y) {
        return m + n + x + y;
    }
    console.log(add(10, 20, 30, 40)); // 100
    
    // 柯里化为
    // 纯函数不存在闭包
    function sum(m) {
       return function (n) {
          return function (x) {
             return function (y) {
                 return m + n + x + y;
             };
          };
       };
    }
    console.log(sum(10)(20)(30)(40)); // 100
    
    // 简化柯里化的代码
    const sum2 = m => n => x => y => m + n + x + y;
    console.log(sum2(10)(20)(30)(40)); // 100
    
    三、为什么有柯里化

    1、单一职责原则:将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结果;

    // 柯里化单一职责原则
    // 原函数
    function add(x, y, z) {
      x = x + 2;
      y = y * 2;
      z = z * z;
      return x + y + z;
    }
    
    console.log(add(10, 20, 30)); // 952
    
    // 柯里化为
    function sum(x) {
      x = x + 2;
      return function (y) {
        y = y * 2;
        return function (z) {
          z = z * z;
          return function () {
            return x + y + z;
          };
        };
      };
    }
    console.log(sum(10)(20)(30)()); // 952
    

    2、逻辑的复用

    function makeAdder(count) {
      return function (num) {
        return count + num;
      };
    }
    
    const result = makeAdder(5)(10); // 15
    console.log(result);
    
    const adder5 = makeAdder(5);
    console.log(adder5(10)); // 15
    console.log(adder5(20)); // 25
    
    function log(date, type, message) {
      console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]:[${message}]`);
    }
    log(new Date(), 'debug', '查找到bug'); // [8:48][debug]:[查找到bug]
    
    // 柯里化的优化
    const log = date => type => message => {
      console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]:[${message}]`)
    }
    const nowLog = log(new Date())
    nowLog('debug')('查找到bug'); // [8:52][debug]:[查找到bug]
    
    四、柯里化函数的实现
    // 普通函数 柯里化
    function cutomCurrying(fn) {
      function curried(...args) {
        // 判断当前接收到的参数个数,是否与函数本身需要接收的参数一致
        // 当已经传入的参数个数 >= 需要的参数个数时,直接执行函数
        if (args.length >= fn.length) {
          // curryAdd使用call时需要绑定作用域
          return fn.apply(this, args);
        }
        // 当已经传入的参数个数 < 需要的参数个数时,返回新的函数继续接收参数
        return function curried2(...args2) {
          // 接收到参数后,需要递归调用curried来检查函数的个数
          // curryAdd使用call时需要绑定作用域
          return curried.apply(this, [...args, ...args2]);
        };
      };
      return curried;
    }
    
    const curryAdd = cutomCurrying(add);
    
    function add(x, y, z) {
      return x + y + z;
    }
    
    console.log(curryAdd(10, 20, 30)); // 60
    console.log(curryAdd(10)(20)(30)); // 60
    console.log(curryAdd(10, 20)(30)); // 60
    
    五、组合函数
    function double(num) {
      return num * 2;
    }
    
    function square(num) {
      return num ** 2;
    }
    
    const count = 10;
    console.log(square(double(count))); // 400
    
    function composeFn(m, n) {
      return function (count) {
        return n(m(count));
      };
    }
    
    const newFn = composeFn(double, square);
    console.log(newFn(10)); // 400
    
    function double(num) {
      return num * 2;
    }
    
    function square(num) {
      return num ** 2;
    }
    
    function cumstomCompose(...fns) {
      const { length } = fns;
      for (let i = 0; i < length; i++) {
        if (typeof fns[i] !== 'function') {
          throw new TypeError('要求都是函数类型');
        }
      }
      return function (...args) {
      let index = 0;
      let result = length ? fns[index].apply(this, args) : args;
      while (++index < length) {
                result = fns[index].call(this, result);
              }
              return result;
            };
    }
    
    const newFn = cumstomCompose(double, square);
    console.log(newFn(10)); // 400
    

    相关文章

      网友评论

          本文标题:函数柯里化

          本文链接:https://www.haomeiwen.com/subject/cyhdbrtx.html