人类高质量JS函数柯里化

举报
北极光之夜。 发表于 2021/09/14 19:49:46 2021/09/14
【摘要】 🌈🌈🌈你好呀,最近还好吗?JS函数柯里化是比较常见也是比较重要的内容。基础并不难理解,下面带你快速了解并使用js函数柯里化~ 芜湖,起飞 🛫

一. 速识概念🚀:

  🌈🌈🌈你好呀,最近还好吗?JS函数柯里化是比较常见也是比较重要的内容。基础并不难理解,下面带你快速了解并使用js函数柯里化~ 芜湖,起飞 🛫

 百度百科对柯里化的定义为:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。概念枯燥难懂,直接看下面的例子。

比如有个add函数,计算两个参数相加的值,一般我们这样写:

function add(a, b) {
        console.log(a + b);
      }
add(1, 2);      

而函数柯里化就是将add函数改为调用一次函数只接受一个参数,如下:

  function curryAdd(a) {
        return function (b) {
          console.log(a + b);
        };
      }
   curryAdd(1)(2);      

它们的返回结果都是一样的,都是3,如下:

在这里插入图片描述
 函数柯里化利用了闭包的效果,引用的变量不会被垃圾回收机制回收,对闭包不熟悉的可以看我这篇文章👉速识闭包:。那为何要大费周章的把函数柯里化呢?它的优缺点如下:

优点:
1.当存在大量相同参数时,参数复用。
2.提前确认,避免每次都重复判断。
3.延迟计算/运行。
缺点:
使用柯里化让程序具有了更多的自由度,但柯里化用到了arguments对象、递归、闭包等,频繁使用会给性能带来影响。所以视情况使用。

下面将详细说明其优点的常用写法。

二.参数复用🚊:

 比如我有如下需求,调用一个函数,将输出国家、职业、姓名:

  function who(country, occupation, name) {
    console.log(`我来自${country},职业是${occupation},我叫${name}`);
  }
  who("中国", "前端开发", "张三");
  who("中国", "前端开发", "李四");
  who("中国", "前端开发", "王五");

在这里插入图片描述
 有一个问题,就是他们都是来自中国,职业都是前端开发,只有名字不一样。但是每次调用函数都要声明,如果有很多个人都这样写岂不是很麻烦啰嗦,所以我们可以柯里化后简便写法:

  function curryWho(country) {
    return function (occupation) {
      return function (name) {
        console.log(`我来自${country},职业是${occupation},我叫${name}`);
      };
    };
  }
  var myName = curryWho("中国")("前端开发");
  myName("张三");
  myName("李四");
  myName("王五");

一样的结果,但是简便了许多,参数能复用,不用每次都传递:
在这里插入图片描述

三.简单封装🚤:

 我们可以简单封装一个函数,可以把一个普通函数传入,返回一个柯里化函数:

      function curry(fn) {
       // 获取传入函数的参数长度
        let len = fn.length;
        // 返回一个函数
        return function temp() {
          // 获取当前已得到参数
          let args = [...arguments];
          // 如果当前获取参数已经大于等于len
          if (args.length >= len) {
             //执行传入函数
            return fn(...args);
          } else {
            // 否则继续返回函数,同时把当前参数传入
            return function () {
              return temp(...args, ...arguments);
            };
          }
        };
      }

封装完毕,就拿第二大点那个函数测试下:

  function who(country, occupation, name) {
    console.log(`我来自${country},职业是${occupation},我叫${name}`);
  }
  var r = curry(who);
  r("a")("b")("c");

柯里化传参数后照样运行:
在这里插入图片描述
延迟执行:

你看上面那个例子,如果我没有传入三个参数是不会执行的:

  var r = curry(who);
  r("a");
  r("b")("c");
  // 只有它会执行
  r("d")("e")("f");

在这里插入图片描述

四.提前确认🚁:

 比如在js中我们使用 addEventListener 来给元素绑定事件,然而在低版本的 ie 浏览器中只能使用 attachEvent ,这样我们在不确定何种浏览器运行情况下可以提前写一个函数在js一开始就执行,判断是否可以使用 addEventListener ,否则使用 attachEvent 。这样一来只用在开始的时候判断一次,不用后面每次都用到addEvenListener时都判断一次是否可用,浪费性能。

// 自创建一个whichEvent函数
 const whichEvent = (function () {
     // 如果存在 addEventListener
        if (window.addEventListener) {
          // 返回一个函数 element为元素,type为事件类型,listener为执行函数,useCapture为是否为捕获流
          return function (element, type, handler, useCapture) {
            element.addEventListener(
              type,
              function (e) {
              // 执行传入的执行函数,同时改变this指向
                handler.call(element, e);
              },
              useCapture
            );
          };
          //  如果浏览器版本低 ,使用 attachEvent
        } else if (window.attachEvent) {
         // 它只有三个参数,element为元素,type为事件类型,handler为执行函数
          return function (element, type, handler) {
            element.attachEvent("on" + type, function (e) {
              handler.call(element, e);
            });
          };
        }
      })();

使用下whichEvent看看,如点击按钮有输出:

<button>test</button>
---------。。。。。略
 var btn = document.querySelector("button");
      whichEvent(btn, "click", function () {
           console.log("北极光之夜。666666");
      });

在这里插入图片描述

五.扩展面试题🚗:

 柯里化函数是面试常考的,下面分享一道经典的面试题。

 实现一个 add 函数,它能实现 add(1,2,3)=6 ; add(1,2)(3)=6 ; add(1)(2)(3)(4)=10 … 参数传入形式与个数不确认,返回参数相加的值。

      function curryAdd() {
      // 定义args ,收集当前参数 , 将arguments变为数组 ,两种方法如下
        var args = [...arguments];
        //   var args = Array.prototype.slice.call(arguments);
        // 因为不确定参数个数,所以定义要返回的函数
        var temp = function () {
          // 把参数持续放到数组存储
          args.push(...arguments);
          //  // 不确定参数个数,继续返回当前函数即可
          return temp;
        };
       // 巧妙点,重写toString方法返回计算结果。详细 看下面解释。
        temp.toString = function () {
          // 利用 reduce方法计算args数组相加的值
          return args.reduce((a, b) => a + b);
        };
        return temp;
      }

 上面利用 temp.toString = function () { 。。。} 重写toString方法返回计算结果。这是为什么呢,那是因为当你 console.log(‘ ’) 里面为一个函数时,它会调用原型上的toString方法把函数隐式转换为字符串输出显示。这样一来,我们可以重写toString方法,让它返回参数计算结果。
  测试一下:

  console.log(curryAdd(1));
  console.log(curryAdd(1, 2, 3));
  console.log(curryAdd(1, 2)(3));
  console.log(curryAdd(1)(2)(3)(4));
  console.log(curryAdd(1)(2, 2, 1)(3)(4));

在这里插入图片描述

六.总结🛬:

  上面就是js函数柯里化的全部内容啦~ 总而言之,柯里化(Currying)就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数。它的优点为:当存在大量相同参数时,参数复用。提前确认,避免每次都重复判断。延迟计算/运行。缺点:使用柯里化让程序具有了更多的自由度,但柯里化用到了arguments对象、递归、闭包等,频繁使用会给性能带来影响。所以,可以结合实际场景使用柯里化函数。

 那么。下次见啦~

在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。