资讯专栏INFORMATION COLUMN

柯里化

Tony / 923人阅读

摘要:从定义中我们可以对柯里化的步骤做一个简要的概括存在一个函数,接受一个函数作为参数,并返回一个函数。若相等,则将参数放入源函数并返回执行结果。

柯里化 高阶函数

在说明柯里化之前,首先需要理解高阶函数的定义

高阶函数是指以函数作为参数的函数,伪代码可以理解为

function higherOrderFunction(fn) {
    console.log(typeof fn) // "function"
    
}
定义

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

从定义中我们可以对柯里化的步骤做一个简要的概括:

存在一个函数currying,接受一个函数source作为参数,并返回一个函数tmpCurrying。

tmpCurrying接收单一参数,并再次返回一个tmpCurrying,直到所有tmpCurrying接收的参数和等于source函数所需的形参数量。

将tmpCurrying收到的所有单一参数按顺序放入source函数,并执行,以获得结果。

实际应用 使用形式

根据如上定义,可以用如下伪码表示柯里化的使用

参数分步输入

// 实现参数分步输入
function sum(a,b,c) {
    return [...args].reduce((pre,next) => (pre + next));
}

// 存在一个函数currying

const curriedSum = currying(sum);

curriedSum(1)(2)(3); // 6;
curriedSum(1, 2)(3); // 6;
curriedSum(1, 2, 3); // 6;

函数抽象,高阶函数封装

// 用于函数抽象,高阶函数封装等
// 存在如下功能函数

function isPhone(number) {
    return /^1[34578]d{9}$/.test(number);
}

function isMail(mail) {
    return /^(w)+(.w+)*@(w)+((.w+)+)$/.test(mail);
}

/*
    可以讲上面两个函数抽象为
    regString.test(targetString);
*/
function check(reg, target) {
    return reg.test(target);
}


/*
    但是每次使用时仍然需要输入正则作为参数,于是考虑利用柯里化的功能,将函数参数拆为两部分,正则 + 校验对象
    假设存在一个柯里化函数currying(fn, reg)
*/



export const checkPhone = currying(check, /^1[34578]d{9}$/);

export const checkMail = currying(check, /^(w)+(.w+)*@(w)+((.w+)+)$/);


/* 
    checkPhone和checkMail此时皆是只需要一个参数targetString的函数
    使用时只需直接使用即可
*/

checkPhone(13111111111); // true;
柯里化实现

想要实现柯里化函数,需要掌握以下知识点

闭包:内层函数可以访问外层函数的变量

Function.length: 函数的length属性表示其声明时的形参数量

arguments: 类数组arguments表示函数调用时的实参列表(或直接使用参数解构,获取实参数组,推荐此种。原因:arguments只是类数组,没有数组方法,不方便使用,需要用结构或apply等方式将其转化为数组)

实现解析

利用闭包将每次多带带输入的参数存入外层函数currying的数组变量args中。

校验当前args的长度与被封装函数的形参数量是否相等,不相等则继续返回接受参数的中间函数。

若相等,则将参数放入源函数并返回执行结果。

实现1---每次只接受一个参数
function currying(src) {
    // 记录源函数的形参长度
    const length = src.length;
    // 参数列表
    const argsPool = [];
    
    return function tmpFn (arg) {
        // 将参数推入参数池
        argsPool.push(arg);
        
        // 长度判断
        if (length > argsPool.length) {
            return tmpFn;
        } else {
            const res = src(...argsPool);
            argsPool = [];
            return res;
        }
    }
}


function sum(a, b, c, d, e, f) {
    return [...arguments].reduce((pre, next) => (pre + next));
}


const _sum = currying(sum);
_sum(1)(2)(3)(4)(5)(6); // 21
实现2:每次接受若干个参数
function currying(src, ...args) {
    // 记录源函数的形参长度
    const length = src.length;
    // 参数列表
    const argsPool = [...args];
    
    return function tmpFn (...args) {
        // 将参数推入参数池
        argsPool.push(...args);
        
        // 长度判断
        if (length > argsPool.length) {
            return tmpFn;
        } else {
            const res = src(...argsPool);
            argsPool = [];
            return res;
        }
    }
}


function sum(a, b, c, d, e, f) {
    return [...arguments].reduce((pre, next) => (pre + next));
}


const _sum = currying(sum);
_sum(1)(2)(3)(4)(5)(6); // 21
_sum(1, 2, 3, 4)(5, 6); // 21
实现3:不规定参数个数,以无参数传入为循环终止标识
function currying(src, ...args) {
    // 参数列表
    let argsPool = [...args];
    
    
    return function tmpFn (...args) {
        if (args.length > 0) {
            argsPool.push(...args);
            return tmpFn;
        } else {
            const res = src(...argsPool);
            argsPool = [];
            return res;
        }
    }
}


function sum(...args) {
    return args.reduce((pre, next) => (pre + next));
}


const _sum = currying(sum);

_sum(1,2,3)(4,5)(); // 15
_sum(1,2)();        // 3

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102321.html

相关文章

  • 高阶函数应用 —— 柯里与反柯里

    摘要:柯里化通用式上面的柯里化函数没涉及到高阶函数,也不具备通用性,无法转换形参个数任意或未知的函数,我们接下来封装一个通用的柯里化转换函数,可以将任意函数转换成柯里化。 showImg(https://segmentfault.com/img/remote/1460000018998373); 阅读原文 前言 在 JavaScript 中,柯里化和反柯里化是高阶函数的一种应用,在这之前...

    wyk1184 评论0 收藏0
  • 前端进击的巨人(五):学会函数柯里(curry)

    摘要:函数柯里化是把支持多个参数的函数变成接收单一参数的函数,并返回一个函数能接收处理剩余参数,而反柯里化就是把参数全部释放出来。但在一些复杂的业务逻辑封装中,函数柯里化能够为我们提供更好的应对方案,让我们的函数更具自由度和灵活性。 showImg(https://segmentfault.com/img/bVburN1?w=800&h=600); 柯里化(Curring, 以逻辑学家Has...

    chengtao1633 评论0 收藏0
  • JavaScript 函数式编程技巧 - 柯里

    摘要:作为函数式编程语言,带来了很多语言上的有趣特性,比如柯里化和反柯里化。在一些函数式编程语言中,会定义一个特殊的占位变量。个人理解不知道对不对延迟执行柯里化的另一个应用场景是延迟执行。不断的柯里化,累积传入的参数,最后执行。作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。 这里可以对照另外一篇介绍 JS 反柯里化 的文章一起看~ 1. 简介 柯里化(Currying)...

    edgardeng 评论0 收藏0
  • JS中的柯里

    摘要:作为函数式编程语言,带来了很多语言上的有趣特性,比如柯里化和反柯里化。个人理解不知道对不对延迟执行柯里化的另一个应用场景是延迟执行。不断的柯里化,累积传入的参数,最后执行。 作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。 这里可以对照另外一篇介绍 JS 反柯里化 的文章一起看~ 1. 简介 柯里化(Currying),又称部分求值(Partial Evalu...

    Hancock_Xu 评论0 收藏0
  • 高级函数技巧-函数柯里

    摘要:如果你对函数式编程有一定了解,函数柯里化是不可或缺的,利用函数柯里化,可以在开发中非常优雅的处理复杂逻辑。同样先看简单版本的方法,以方法为例,代码来自高级程序设计加强版实现上面函数,可以换成任何其他函数,经过函数处理,都可以转成柯里化函数。 我们经常说在Javascript语言中,函数是一等公民,它们本质上是十分简单和过程化的。可以利用函数,进行一些简单的数据处理,return 结果,...

    shixinzhang 评论0 收藏0
  • JavaScript 函数式编程技巧 - 反柯里

    摘要:作为函数式编程语言,带来了很多语言上的有趣特性,比如柯里化和反柯里化。而反柯里化,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。 可以对照另外一篇介绍 JS 柯里化 的文章一起看~ 1. 简介 柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩...

    zhjx922 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<