阅读 2474

函数柯里化(面试题)包懂,不懂我改。

(柯里化函数是高阶函数的一种特殊应用。对的,在我看来:要明白函数柯里化,前置知识点只有“高阶函数”。高级函数对于咱们每个前端程序员来说,经常用,不难。只不过我们(基础不牢的初级程序员)对于高级函数的定义不是十分明确。所以本片文章分为两个部分:1、高级函数。2、“特殊应用”高级函数。)

一、什么是高阶函数?

  1. 如果一个函数的参数是一个函数 (回调函数就是一种高阶函数)

  2. 如果一个函数返回(return)一个函数 当前这个函数也是一个高阶函数

    典型例子:(既有回调函数,也有把函数当作参数返回

    // 写了一个业务代码,扩展当前的业务代码
    function person(sex){
       console.log(sex);
    }
    // 给某个方法 添加一个方法并在他执行之前调用
    Function.prototype.before = function (callback) {
       return (...args)=>{ // 剩余运算符, 箭头函数没有this(向上找) 也没有arguments (return一个函数)
           callback();    //执行传过来的匿名函数
           this(...args); // 执行this。可以暂时理解谁调用的this就指向谁:person.before  say调用的所以say指向say-
       }
    }
    let personBornRace = person.before(function(){//出生之前就已经知道肤色
       console.log('yellow')
    })//将返回的函数赋值给beforeSay (参数函数)
    personBornRace('男');//出生时才知道男女
    personBornRace('女');
    复制代码

    运行结果:

    yellow
    男
    yellow
    女
    复制代码

二、“特殊应用”高级函数(柯里化)

假设一个场景,做一个判断变量类型功能(我们如何知道一个变量的类型呢)。常用的方法有四种(知识补充):

  1. typeof 不能判断对象类型 typeof [] typeof {} 缺陷是不能判断引用类型

  2. constructor 可以找到这个变量是通过谁构造出来的

  3. instanceof 判断谁是谁的实例 __proto__

  4. Object.prototype.toString.call() 缺陷就是不能细分是谁谁的实例

    我们现在选择第四种方法来做判断数据类型这个功能,这个时候我们可以想到的是:

    /*ps:接下来所假设的场景及后续的代码是借鉴别人的。不过注释及思路是自己组织的语言。我自
    己本来想了一个律师的日常工作(接手各种不同类型的案子)的例子,写出来之后分人家一一对比
    发现真的是不如人家的好。所以恬不知耻的继续用了,至于原出处是已经给不出来了*/  
    function isType(type,value) {
        return Object.prototype.toString.call(value) === `[object ${type}]`;
    }
    console.log(isType('Array',[]))
    复制代码

    运行结果:

    true
    复制代码

    挺完美的吧,简简单单一句就可以完成。的确,在这个场景中这的确就是最优解。但是在实际开发中呢,有很大可能是需要处理大量不同类型的变量,每一次调用都要我们自己编写两个参数,尤其是Array这个字符串变量,有可能一个不小心写错,但是编译器却不会报错,并且很难找到错误在哪里。如下:

    console.log(isType([],'Arary');//Arary写错了
    复制代码

    运行结果:

    false //? ? 怎么就错了 ?
    复制代码

    所以这个时候我们就想能不能做一件事情,就是将方法细分。细分成isArray isString(柯里化)。
    说人话就是:利用高级函数提前把其中一个变量写好。调用的时候只需要填写一个变量就好。

    function isType(type) {
       return function(value) {
           return Object.prototype.toString.call(value) === `[object ${type}]`;
       }
    }
    let isArray = isType('Array');//提前写好了Array  并把isType赋值给isArray
    //这个时候我们就可以只传我们想校验的变量就可以了,Array早已经写死。
    console.log(isArray('hello'));
    console.log(isArray([]));
    复制代码

    执行结果:

    false
    true
    复制代码

    以上就是最基础的函数柯里化,但是如果真的只有那么简单,怎么可以配得上柯里化这么一个高大上的名字呢?怎么可以应用的各种各样的复杂需求场景里呢?所以上面的函数可以需要升级,需要公式化,不同的场景中都可以用一个通用的函数来套用。

    通用的函数柯里化(封装):对比上面的代码可以看懂。

    function isType(type,value) {
        return Object.prototype.toString.call(value) === `[object ${type}]`;
    }
    //通用  公式 可以套用
    //这里有一个地方我是没有弄明白的:”type = []“,在括号里面声明。
    const currying = (fn,type = []) => {
        let len = fn.length;//这里是函数形参(并未调用,还没传值)的长度
        return function(...args) {
            let concatValue = [...type,...args];
            if(concatValue.length < len) {
                return currying(fn,concatValue);
            } else {
                return fn(...concatValue);
            }
        }
    }
    
    let isArray = currying(isType)('Array');//执行currying,传实参isType,执行return回来的函数同时传实参‘Array’,并把最后返回出来的fn(是刚才传进去的isType)赋值给isArray。其中处理看代码
    let isString = currying(isType)('String');
    console.log(isArray([]))
    console.log(isArray('123'))
    console.log(isString([]));
    console.log(isString('123'));
    复制代码

    输出结果

    true
    false
    false
    true
    复制代码

ps:我在想,怎么把上面整篇文字写成一个故事。哈哈
标题说了大话,但我应该可以坚持一下
故事来啦:js魔法王国中,函数工程院的魔法师正在进行一天的日常工作。毕业于某魔法学院一阶魔法师阿冠今天也进行着和往常一样的枯燥工作:准备一系列js魔法王国基建工程的基础魔法。比如将a 和 b 相加得到 c 的‘合(数字)’魔法啊;再比如把c,d,e,f赋予意义(var name='a'; var age='b';)的‘声明’魔法啊;稍微有意思点的还有感知周围最近空间document.getElementById("box").offsetWidth 的感知魔法。

今天也不例外,今天他需要将字符串'https://','suppliertest.xiaonianyu.com/','login'用‘合’魔法合起来。其实魔法师阿冠认为自己挺天才的,因为他知道今天他所准备的魔法释放(调用)后是可以起到传送的作用的。‘传送魔法哎,就算是函数工程院的四阶大魔法师也就会个传送魔法吧!函数研究院的魔导师们难道还可以做出比传送魔法更厉害的魔法来吗?!大魔法师们的感知魔法,自己也会,而且威力也不差’,阿冠暗自得意着。

花费了一些时间,阿冠终于把这个基础‘合’魔法做好了。现在他需要把这个基础魔法送到自己在工程院的导师那里去,在路上阿冠一直在想刚才他自己所想的事情,四阶大魔法师能做的事情自己也能做到,自己和大魔法师的实际差别到底在哪里呢?或许等会见到导师如果看他心情不错的话自己可以跟导师请教一下。

“导师,‘合’基础魔法我给您送过来了。”,“嗯好”,导师颇为平静的把基础魔法收录下来。阿冠这时候在旁边察言观色,发现导师神色和蔼,眼神波澜不起,心情不错的样子,于是借机将自己的疑问提了出来:“导师,我发现我可以做出和四阶大魔法师一样的魔法,而且威力是一样的,我没有发现我和大魔法师的差别在哪里,就拿我刚才交给您的这个魔法来说,他释放以后可以是一个传送魔法,大魔法师最后用我这些基础魔法做出来的魔法也是一个传送魔法。”导师听完我的疑问,一边思考一边慢慢对我说到:“你说的没有错,的确在目前看来两个魔法是发挥了一样的威力,但是你有没有想过这个传送魔法是js魔法王国交通大基建关键魔法,基建魔法,就证明了这个魔法是给王国中所有人用的,其中绝大部分使用者都不是传送魔法专精,或者他不清楚自己要去的地方的具体坐标,只知道一个模糊的位置。当这遇到这些问题时候你的这个魔法还能顺利释放吗?” 说到这里,导师停了下来,(凌晨,先不写了。明天还要上班,小命要紧。待续……)

关注下面的标签,发现更多相似文章
评论