zoukankan      html  css  js  c++  java
  • 555 柯理化函数,组合函数 compose

    柯理化函数

    柯理化函数编程思想:利用闭包的保存机制,事先把一些信息存储起来(存储到不释放的上下文中),这样可以供下级上下文中调用,我们把这种预先存储的思想叫做柯理化函数编程思想

    function fn(...outerArgs) {
      // outerArgs = [1,2]
      return function anonymous(...innerArgs) {
        // innerArgs = [3]
        let args = outerArgs.concat(innerArgs); // 可以用[...outerArgs, ...innerArgs]
        return args.reduce((sum, item) => {
          return sum + item;
        }, 0);
      }
    }
    let res = fn(1, 2)(3);
    console.log(res); // => 6  1 + 2 + 3
    
    
    // reduce依次遍历数组中的每一项,每一次遍历都会触发回调函数执行
    // n:如果reduce不传递第二个参数,第一次获取的是数组第一项,其余每一次获取的值是上一次回调函数处理的结果(传递第二个参数,第一次获取的是第二个实参信息)
    // m:依次遍历的数组每一项
    let arr = [10, 20, 30, 40];
    let total = arr.reduce((n, m) => {
      // 第一次: n = 10,m = 20
      // 第二次:n = 30,m = 30
      // 第三次:n = 60,m = 40
      console.log(n, m);
      return n + m; // 这里有返回值,如果没有指定返回值,就是返回undefined
    });
    console.log(total);
    
    
    // 补充代码
    let fn = function fn(...args1) {
      return function fn2(...args2) {
        return function (...args3) {
          let arr = [...args1, ...args2, ...args3]
          console.log(arr)
          return arr.reduce((a, b) => {
            console.log(a, b)
            return a + b
          }, 0)
        }
      }
    }
    
    let res = fn(1, 2)(3)(4);
    console.log(res); // 10
    

    组合函数 compose

    在函数式编程当中有一个很重要的概念就是函数组合, 实际上就是把处理数据的函数像管道一样连接起来, 然后让数据穿过管道得到最终的结果。 例如:

    const add1 = (x) => x + 1;

    const mul3 = (x) => x * 3;

    const div2 = (x) => x / 2;

    div2(mul3(add1(add1(0)))); // 3

    而这样的写法可读性明显太差了,我们可以构建一个compose函数,它接受任意多个函数作为参数(这些函数都只接受一个参数),然后compose返回的也是一个函数,达到以下的效果:

    const operate = compose(div2, mul3, add1, add1)

    operate(0) //=>相当于div2(mul3(add1(add1(0))))

    operate(2) //=>相当于div2(mul3(add1(add1(2))))

    简而言之:compose可以把类似于f(g(h(x)))这种写法简化成compose(f, g, h)(x),请你完成 compose函数的编写

    // funcs: 存储的是最后需要按照顺序依次执行的函数集合
    function compose(...funcs) {
      // 要返回一个函数,外面才能传参调用
      return function anonymous(...args) {
        // args: 存储的是给第一个函数执行传递的实参集合
        if (funcs.length === 0) return args.length <= 1 ? args[0] : args;
        if (funcs.length === 1) return funcs[0](...args);
        // funcs = [add1, add1, mul3, div2]
        // args = [0]
        /* 
        return funcs.reduce((result, item) => {
          // 通过判断是否是函数类型
          return typeof result === "function" ?
            item(result(...args)) :
            item(result);
        }); 
        */
    
        // 不用判断是否是函数类型
        let n = 0;
        return funcs.reduce((result, item) => {
          n++;
          return n === 1 ? item(result(...args)) : item(result);
        });
      };
    }
    
    const add1 = (x) => x + 1;
    const mul3 = (x) => x * 3;
    const div2 = (x) => x / 2;
    
    // => 0 如果不指定任何函数, 直接把最后传递的结果返回,传递一个返回一个值,传递多个返回一个数组
    let result = compose()(0);
    console.log(result);
    
    // => add1(0) 只指定一个函数,就是把最后的结果传递这个函数,执行函数获取其返回值即可
    result = compose(add1)(0);
    console.log(result);
    
    result = compose(add1, add1, mul3, div2)(0);
    console.log(result);
    
    
    // --------------------------
    
    
    Array.prototype.reduce = function reduce(callback) {
      // this -> arr
      let result = this[0];
      for (let i = 1; i < this.length; i++) {
        let item = this[i];
        if (typeof callback === "function") {
          result = callback(result, item);
        }
      }
      return result;
    };
    
    let arr = [10, 20, 30, 40];
    let result = arr.reduce((a, b) => {
      return a + b;
    });
    console.log(result);
    

    惰性函数

    // JS中的事件绑定 DOM2事件绑定
    // => 新版浏览器中: [元素].addEventListener([type],[func])
    // => 老版浏览器中:[元素].attachEvent([on+type],[func])
    // 都不支持  [元素].ontype=[func]
    // 属性 in 对象:检测对象中是否存在这个属性
    
    /* 惰性思想:懒,能够执行一次搞定的,绝对不会重复干两次 */
    function handleEvent(element, type, func) {
      if ('addEventListener' in element) {
        element.addEventListener(type, func);
      } else if ('attachEvent' in element) {
        element.attachEvent('on' + type, func);
      } else {
        element['on' + type] = func;
      }
    }
    
    
    // -----------------------
    
    
    // 第二次调用handleEvent的时候,就是调用重写后的handleEvent了
    function handleEvent(element, type, func) {
      if ('addEventListener' in element) {
        handleEvent = function (element, type, func) {
          element.addEventListener(type, func);
        };
      } else if ('attachEvent' in element) {
        handleEvent = function (element, type, func) {
          element.attachEvent('on' + type, func);
        };
      } else {
        handleEvent = function (element, type, func) {
          element['on' + type] = func;
        };
      }
      // 第一次执行重写方法后,需要执行一次,才能保证第一次事件也绑定了
      handleEvent(element, type, func);
    }
    
    handleEvent(document.body, 'click', function () {
      console.log('BODY点击');
    });
    
    handleEvent(document.documentElement, 'mouseenter', function () {
      console.log('HTML进入');
    });
    

  • 相关阅读:
    python的paramiko模块简单应用
    python单线程下实现多个socket并发
    python之协程
    python之生产者消费者模型
    python进程之间修改数据[Manager]与进程池[Pool]
    python的进程间的数据交互
    vmware搭建vSAN提示磁盘不合格或者看不到磁盘的解决办法
    python之多并发socket
    OOP的几个不常用的方法
    HTTP 头和 PHP header() 函数
  • 原文地址:https://www.cnblogs.com/jianjie/p/13857296.html
Copyright © 2011-2022 走看看