千家信息网

JavaScript函数柯里化是什么

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章将为大家详细讲解有关JavaScript函数柯里化是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、简单了解apply和callcall 和 appl
千家信息网最后更新 2026年11月03日JavaScript函数柯里化是什么

这篇文章将为大家详细讲解有关JavaScript函数柯里化是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

一、简单了解apply和call

  • call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。

  • call 和 apply二者的作用完全一样,只是接受参数的方式不太一样。call其实是apply的一种语法糖。

  • 格式:apply(context,[arguments]),call(context,param1,param2,...)。

二、什么是函数柯里化?

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

在这里举个例子,有一个add()函数,它是用来处理我们传给它的参数(param1,params2,…)相加求和的一个函数。

// 在这里第一个具有两个参数`x`、`y`的`add(x , y)`函数function add(x , y){        return x + y;}// 调用`add()`函数,并给定两个参数`4`和`6`add(4,6);// 模拟计算机操作,第一步 传入第一个参数 4function add(4 , y){        return 4 + y;}// 模拟计算机操作,第二步 传入第一个参数 6function add(4 , 6){        return 4 + 6;}

如果我们将add()函数柯里化,是什么样子呢?在这里简单的实现一下:

// 柯里化过的add()函数,可以接受部分参数function add(x ,y){        if (typeof y === 'undefined') {                return function (newy){                        return x + newy;                }        }        // 完整应用        return x + y;}// 测试调用console.log(typeof add(4)); // [Function]console.log(add(4)(6)); // 10// 可以创建保存函数let saveAdd = add(4);console.log(saveAdd(6)); // 10

从以上简单柯里化的add()函数可以看出,函数可以接受部分函数,然后返回一个新的函数,使其继续处理剩下的函数。

三、写一个公共的柯里化函数

在这里我们创建一个公共的柯里化函数,那样我们就不必每次写一个函数都要在其内部实现复杂的柯里化过程。

// 定义一个createCurry的函数function createCurry(fn){        var slice = Array.prototype.slice,        stored_args = slice.call(arguments,1);                return function () {                let new_args = slice.call(arguments),                args = stored_args.concat(new_args);                return fn.apply(null,args);        }}

在以上公共的柯里化函数中:

  • arguments,并不是一个真的数组,只是一个具有length属性的对象,所以我们从Array.prototype中借用slice方法帮我们把arguments转为一个真正的数组,方便我们更好的操作。

  • 当我们第一次调用函数createCurry的时候,其中变量stored_args 是保持了除去第一个参数以外的参数,因为第一个参数是我们需要柯里化的函数。

  • 当我们执行createCurry函数中返回的函数时,变量new_args获取参数并转为数组。

  • 内部返回的函数通过闭包访问变量stored_args中存储的值和变量new_args的值合并为一个新的数组,并赋值给变量args。

  • 最后调用fn.apply(null,args)方法,执行被柯里化的函数。

现在我们来测试公共的柯里化函数

// 普通函数add()function add(x , y){        return x + y;}// 柯里化得到一个新的函数var newAdd = createCurry(add,4);console.log(newAdd(6)); // 10//另一种简便方式console.log(createCurry(add,4)(6));// 10

当然这里并不局限于两个参数的柯里化,也可以多个参数:

// 多个参数的普通函数function add(a,b,c,d){        return a + b + c + d;}// 柯里化函数得到新函数,多个参数可以随意分割console.log(createCurry(add,4,5)(5,6)); // 20// 两步柯里化let add_one = createCurry(add,5);console.log(add_one(5,5,5));// 20let add_two = createCurry(add_one,4,6);console.log(add_two(6)); // 21

通过以上的例子,我们可以发现一个局限,那就是不管是两个参数还是多个参数,它只能分两步执行,如以下公式:

  • fn(x,y) ==> fn(x)(y);

  • fn(x,y,z,w) ==> fn(x)(y,z,w) || fn(x,y)(z,w)||…

如果我们想更灵活一点:

  • fn(x,y) ==> fn(x)(y);

  • fn(x,y,z) ==> fn(x,y)(z) || fn(x)(y)(z);

  • fn(x,y,z,w) ==> fn(x,y)(z)(w) || fn(x)(y)(z)(w) || …;

我们该怎么实现呢?

四、创建一个灵活的柯里化函数

经过以上练习,我们发现我们创建的柯里化函数存在一定局限性,我们希望函数可以分为多步执行:

// 创建一个可以多步执行的柯里化函数,当参数满足数量时就去执行它:// 函数公式:fn(x,y,z,w) ==> fn(x)(y)(z)(w);let createCurry = (fn,...params)=> {        let args = parsms || [];        let fnLen = fn.length; // 指定柯里化函数的参数长度                return (...res)=> {                // 通过作用域链获取上一次的所有参数                let allArgs = args.slice(0);                // 深度拷贝闭包共用的args参数,避免后续操作影响(引用类型)                allArgs.push(...res);                if(allArgs.length < fnLen){                   // 当参数数量小于原函数的参数长度时,递归调用createCurry函数                   return createCurry.call(this,fn,...allArgs);                }else{                  // 当参数数量满足时,触发函数执行                  return fn.apply(this,allArgs);                }        }}// 多个参数的普通函数function add(a,b,c,d){        return a + b + c + d;}// 测试柯里化函数let curryAdd = createCurry(add,1);console.log(curryAdd(2)(3)(4)); // 10

以上我们已经实现了灵活的柯里化函数,但是这里我们又发现了一个问题:

  • 如果我第一次就把参数全部传入,但是它并没有返回结果,而是一个函数(function)。

  • 只有我们再次将返回的函数调用一次才能返回结果:curryAdd(add,1,2,3,4)();

  • 可能有人说如果是全部传参,就调用原来的add()函数就行了,这也是一种办法;但是我们在这里既然是满足参数数量,对于这种情况我们还是处理一下。

在这里我们只需要在返回函数前做一下判断就行了:

let createCurry = (fn,...params)=> {        let args = parsms || [];        let fnLen = fn.length; // 指定柯里化函数的参数长度                if(length === _args.length){           // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果           return fn.apply(this,args);        }        return (...res)=> {                let allArgs = args.slice(0);                allArgs.push(...res);                if(allArgs.length < fnLen){                   return createCurry.call(this,fn,...allArgs);                }else{                  return fn.apply(this,allArgs);                }        }}

以上可以算是完成了一个灵活的柯里化的函数了,但是这里还不算很灵活,因为我们不能控制它什么时候执行,只要参数数量足够它就自动执行。我们希望实现一个可以控制它执行的时机该怎么办呢?

五、写一个可控制的执行时间的柯里化函数

我们这里直接说明一下函数公式:

  • fn(a,b,c) ==> fn(a)(b)(c )();

  • fn(a,b,c) ==> fn(a);fn(b);fn(c );fn();

  • 当我们参数足够时它并不会执行,只有我们再次调用一次函数它才会执行并返回结果。在这里我们在以上例子中加一个小小的条件就可以实现。

// 当参数满足,再次执行时调用函数let createCurry = (fn,...params)=> {        let args = parsms || [];        let fnLen = fn.length; // 指定柯里化函数的参数长度                //当然这里的判断需要注释掉,不然当它第一次参数数量足够时就直接执行结果了        //if(length === _args.length){           // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果           //return fn.apply(this,args);        //}        return (...res)=> {                let allArgs = args.slice(0);                allArgs.push(...res);                // 在这里判断输入的参数是否大于0,如果大于0在判断参数数量是否足够,                // 这里不能用 && ,如果用&& 也是参数数量足够时就执行结果了。                if(res.length > 0 || allArgs.length < fnLen){                   return createCurry.call(this,fn,...allArgs);                }else{                  return fn.apply(this,allArgs);                }        }}// 多个参数的普通函数function add(a,b,c,d){        return a + b + c + d;}// 测试可控制的柯里化函数let curryAdd = createCurry(add,1);console.log(curryAdd(2)(3)(4)); // functionconsole.log(curryAdd(2)(3)(4)()); // 10console.log(curryAdd(2)(3)()); // 当参数不足够时返回 NaN

关于"JavaScript函数柯里化是什么"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

函数 参数 柯里 数量 结果 多个 变量 第一次 普通 两个 数组 长度 控制 测试 例子 公式 再次 篇文章 处理 作用 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司怎么样 深圳恒合互联网络科技有限公司 互联网与科技发展 互联网络科技有限公司 平安科技 互联网 奇酷互联网科技公司 唐信互联网科技 成都互联网科技公司 智慧科技互联网 济南华为互联网科技产业总部基地 贵州叶脉互联网科技有限公司所属行业 湖南一路畅行互联网科技 未来五年的互联网科技 中国科技创新与世界互联网大会 科技互联网的核心竞争力 互联网界的黑科技 唐山双旺合互联网科技产业园 互联网科技大佬云集 瑞安市蟠桃会互联网科技有限公司 六子台科技互联网展会 科技类互联网 中国 科技 互联网 有木互联网科技 厦门比较好的科技互联网公司 中国航天科技大学国际工业互联网 山东有哪些互联网科技公司 半导体是互联网高科技吗 国产互联网科技公司 互联网科技收购价值 北京军民互联网科技公司
0