柯里化

柯里化

高阶函数

在申明柯里化之前,起首须要明白高阶函数的定义

高阶函数是指以函数作为参数的函数,伪代码能够明白为

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

定义

在计算机科学中,柯里化(Currying)是把吸收多个参数的函数变换成吸收一个单一参数(最初函数的第一个参数)的函数,而且返回吸收余下的参数且返回效果的新函数的手艺。

从定义中我们能够对柯里化的步骤做一个扼要的归纳综合:

  1. 存在一个函数currying,吸收一个函数source作为参数,并返回一个函数tmpCurrying。
  2. tmpCurrying吸收单一参数,并再次返回一个tmpCurrying,直到一切tmpCurrying吸收的参数和即是source函数所需的形参数目。
  3. 将tmpCurrying收到的一切单一参数按递次放入source函数,并实行,以取得效果。

现实运用

运用情势

依据如上定义,能够用以下伪码示意柯里化的运用

  1. 参数分步输入
// 完成参数分步输入
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;
  1. 函数笼统,高阶函数封装
// 用于函数笼统,高阶函数封装等
// 存在以下功用函数

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;

柯里化完成

想要完成柯里化函数,须要控制以下知识点

  1. 闭包:内层函数能够接见外层函数的变量
  2. Function.length: 函数的length属性示意其声明时的形参数目
  3. arguments: 类数组arguments示意函数调用时的实参列表(或直接运用参数解构,猎取实参数组,引荐此种。缘由:arguments只是类数组,没有数组要领,不方便运用,须要用构造或apply等体式格局将其转化为数组)

完成剖析

  1. 应用闭包将每次零丁输入的参数存入外层函数currying的数组变量args中。
  2. 校验当前args的长度与被封装函数的形参数目是不是相称,不相称则继承返回吸收参数的中心函数。
  3. 若相称,则将参数放入源函数并返回实行效果。

完成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
    原文作者:Heptagon
    原文地址: https://segmentfault.com/a/1190000018369228
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞