函数柯里化

柯里化

定义

柯里化currying是一种函数的高阶技术,用于转换函数,将函数从f(a,b,c)转换为f(a)(b)(c)或者f(a,b)(c)或者f(a)(b,c)

柯里化不会调用函数,只是对函数进行转换。

柯里化也可以理解为部分求值,接收部分参数后,不会立即求值,而是返回一个接受剩余参数的函数。可以缩小函数的适用范围,创建一个针对性更强的函数,又称为偏应用型函数。

假设有一个求和的函数sum,设计一个curry函数使其柯里化。

r 复制代码
const sum = function(a,b,c){
    return a+b+c;
}

调用柯里化的函数满足以下结果:

scss 复制代码
sum(1,2,3) // 6
sum(1)(2,3) // 6
sum(1,2)(3) // 6
sum(1)(2)(3) // 6

根据柯里化暂存参数返回一个新偏函数的特点来设计柯里化辅助函数curry:

javascript 复制代码
const currySum = function(fn){
    return function(a){
        return function(b){
            return function(c){
                return sum(a,b,c);
             }
        }
    }
}
const newSum = currySum(sum);
console.log(newSum(1)(2)(3)); // 6

目前设计的curry函数只能满足f(a)(b)(c)形式的调用,其他形式的调用会报错。而且curry函数内部有多层函数嵌套的回调函数,造成代码的重复和难以维护。

柯里化有更高级的实现,例如 lodash 库的_.curry,其会返回一个包装器,该包装器允许函数被正常调用或者以任何偏函数的方式调用。

通用公式

函数柯里化又分为固定参数和任意参数。

  1. 固定参数个数,原函数参数确定
scss 复制代码
function myCurry(fn){
    return function curried(...args){
        if(args.length >= fn.length){
            return fn.apply(this,args);
        }else{
            return function(...args2){
                return curried.apply(this,args.concat(args2));
            }
        }
    }
}

const newSum1 = myCurry(sum);
console.log(newSum1(1,2,3)); // 6
console.log(newSum1(1)(2)(3)); // 6
console.log(newSum1(1,2)(3)); // 6
console.log(newSum1(1)(2,3)); // 6
  1. 任意参数个数,原函数参数长度不确定
ini 复制代码
const add = (...args) => {
    let vars = args;
    const curried = (...args) => {
        vars = [...vars, ...args];
        return curried;
    };
    curried.toString = () => {
        return vars.reduce((a, b) => a + b, 0);
    };
    return curried;
};

const res = add(1); // 1
const res = add(1,2,3); // 6
const res = add(1)(2)(3); // 6
const res = add(1)(2,3)(4)(5); // 15

console.log(res.toString(),'res是一个函数,需要调用其toString方法获取值');

优缺点

柯里化函数的优点:

  • 灵活性:将多个参数的函数转换成一系列只接受单个参数的函数,可以灵活地组合和使用函数

  • 可复用性:将柯里化函数的一部分参数预设,从而得到新的函数,该函数可以直接使用,也可以作为其他函数的参数使用

柯里化函数的缺点:

  • 可读性:原函数的调用变得更复杂,需要多次调用不同的函数才能得到最终结果,降低了代码的可读性

适应场景

  • 缩小函数适用范围:当函数需要传递一部分参数时,可以使用柯里化函数将该部分参数预设,从而得到新的函数

  • 参数复用:将一部分参数固化,反复使用

  • 延迟执行函数

scss 复制代码
const curryAdd = function(...rest){
    const args = rest;
    return function cb(...rest) {
        if (rest.length === 0) {
            return args.reduce((a, b) => a + b, 0);
        } else {
            args.push(...rest);
            return cb;
        }
    };
}()

curryAdd(1);
curryAdd(2);
curryAdd(); // 3
  • 简化参数传递:当函数需要多个参数时,可以使用柯里化函数将多个参数转换成一系列只接受单个参数的函数,从而简化参数传递

反柯里化

定义

反柯里化是将柯里化函数转换成接受多个参数的函数的过程。

反柯里化函数的返回值是一个函数,该函数接受一个对象作为参数,并调用该对象的原本方法并传递参数。

反柯里化的作用在于扩大函数的适用性,使本来只有特定对象所拥有的函数可以被任意对象所用。

例如将obj.func(arg1, arg2)转换为func(obj, arg1, arg2)的函数形式调用。

目前有一个对象obj和一个求和的函数,需要调用求和函数并让this指向obj

kotlin 复制代码
const obj = {a:1,b:2};

function sum(){
    return this.a + this.b;
}

可以通过.call.apply改变this指针指向

ini 复制代码
const res = sum.call(obj); // 3

也可以利用bind固化this指向并返回一个新函数

ini 复制代码
const newSum = sum.bind(obj);
console.log(newSum()); // 3

通用公式

javascript 复制代码
function uncurrying(fn){
    return function(){
        const context = Array.from(arguments).slice(1);
        return fn.apply(context,arguments);
    }
}

优缺点

反柯里化函数的优点:

  • 可读性:函数的调用变得更简单,只需要调用一个函数并传递一个对象作为参数即可

  • 可复用性:将一个预设 this 对象的函数转换成接受 this 对象的函数,从而可以在不同的对象上复用该函数

反柯里化函数的缺点:

  • 灵活性:函数的 this 对象变得固定,降低了函数的灵活性

适用场景

  • 复用函数:当多个对象需要调用同一个方法时,可以使用反柯里化函数将该方法转换成接受对象作为参数的函数,从而可以在不同的对象上复用该函数

  • 链式调用:当多个方法需要进行链式调用时,可以使用反柯里化函数将该方法转换成接受对象作为参数的函数,从而可以方便地进行链式调用

相关推荐
hahala233316 分钟前
ESLint 提交前校验技术方案
前端
夕水39 分钟前
ew-vue-component:Vue 3 动态组件渲染解决方案的使用介绍
前端·vue.js
我麻烦大了42 分钟前
实现一个简单的Vue响应式
前端·vue.js
独立开阀者_FwtCoder1 小时前
你用 Cursor 写公司的代码安全吗?
前端·javascript·github
Cacciatore->1 小时前
React 基本介绍与项目创建
前端·react.js·arcgis
摸鱼仙人~1 小时前
React Ref 指南:原理、实现与实践
前端·javascript·react.js
teeeeeeemo1 小时前
回调函数 vs Promise vs async/await区别
开发语言·前端·javascript·笔记
贵沫末1 小时前
React——基础
前端·react.js·前端框架
aklry2 小时前
uniapp三步完成一维码的生成
前端·vue.js
Rubin932 小时前
判断元素在可视区域?用于滚动加载,数据埋点等
前端