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进入');
    });
    

  • 相关阅读:
    eslint 的 env 配置是干嘛使的?
    cookie httpOnly 打勾
    如何定制 antd 的样式(theme)
    剑指 Offer 66. 构建乘积数组
    剑指 Offer 65. 不用加减乘除做加法
    剑指 Offer 62. 圆圈中最后剩下的数字
    剑指 Offer 61. 扑克牌中的顺子
    剑指 Offer 59
    剑指 Offer 58
    剑指 Offer 58
  • 原文地址:https://www.cnblogs.com/jianjie/p/13857296.html
Copyright © 2011-2022 走看看