关于Add(2)(3)问题

本文探讨了JavaScript中Currying的概念及其应用,通过add函数的不同实现展示了如何处理多个参数及连续调用。提供了多种实现方案,包括利用valueOf属性、显式调用属性以及通过高阶函数实现通用解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于Add(2)(3)问题

首先,add(2)(3)用JavaScript 实现

首先,如果我们做一个简单的分析,我们可以简单地说这不仅仅是针对JavaScript的问题,而是可以用任何具有First Class功能的语言实现。

当该语言中的函数被视为与任何其他变量一样时,编程语言被称为具有第一类函数。例如,在这种语言中,函数可以作为参数传递给其他函数,可以由另一个函数返回,并可以作为值赋值给变量。

现在我们只需要创建一个返回另一个函数的函数,该函数反过来会给出总和。而已。

在继续之前,如果您是第一次遇到此问题,请自行尝试此问题。

解,

function add(x){
    return function (y){
        return x+y;
    }
}

也可以使用箭头函数在ES6中实现,

const add = x => y => x+y;

这个问题只不过currying是JS中的概念。

什么是currying?

Currying是一种将具有多个参数的函数评估为具有单个/多个参数的函数序列的技术。在上述问题中,我们只需打开了add(2,3)进入add(2)(3)

你可以从这篇文章中深入讨论

add(2)(3)问题的变体

也可以看到这种干扰问题的变化很少

add(2)(3)(4)...,用于无数个参数

嗯,我们知道如何处理求和和返回函数(以及闭包)但我们不确定何时停止,这意味着,主函数何时返回结果以及何时返回另一个curried函数。可能有两种选择,

1.利用valueOf财产

我们已经ToPrimitive在本博客中看到了JS引擎如何处理操作。考虑到这一事实,如果我们返回一个对象(或函数),其valueOf属性返回到目前为止计算的结果,我们将能够区分返回函数以进行进一步求和到目前为止的求和结果。让我们来看看,

function add(x){
    let sum = x;
    function resultFn(y){
        sum += y;
        return resultFn;
    }
    resultFn.valueOf = function(){
            return sum;
        };
    return resultFn;
}

以下执行可行,

> 5 + add(2)(3) //output: 10
> console.log(add(2)(3)(4)==9) //output: true
> add(3)(4)(5).valueOf() //output: 12

另一方面,例如,这将无法工作或意外地在少数地方出现

> add(3)(4)(5) //return function
> console.log(add(3)(4)(5)) // output: function
> console.log(add(3)(4)(5)===12)// output: false

这种行为是由于valueOfJS引擎在需要将add(2)(3)(4)的结果转换为基本类型时将调用该属性。上述所有给出正确结果的语句都是由于JS引擎试图将结果转换为原始值。

2.明确要求财产

另一种方法可能是,我们遵循一个约定,函数的使用者应该在结果中显式调用属性来获得求和。此解决方案与使用的解决方案非常相似valueOf,但不会发生隐式转换。像这样的东西,

function add(x){
    let sum = x;
    return function resultFn(y){
        sum += y;
        resultFn.result = sum;
        return resultFn;
    }
}

消费将是,

> add(3)(4)(5).result //output: 12
> var t = add(3)(4);
> t.result //output: 7
> t(5).result //output: 12

如果必须实现这种类型的东西,它应该是通过模块/类,而不是简单的函数来模拟行为。

3.显式调用函数,没有最终结果的参数

还可以设计函数以在没有参数的情况下调用函数时返回结果求和。如果传递参数,它将继续将这些数字添加到先前的结果。

function add(x){
    let sum = x;
    return function resultFn(y){
        if(arguments.length){ //not relying on falsy value
            sum += y;
            return resultFn;
        }
        return sum;
    }
}

这可以用以下方式,

> add(2)(3)() //output: 5
> var t = add(3)(4)(5)
> t() //output: 12
add(2)(3)(4) and add(2,3,4) 在同一功能中使用。

这是另一个方差,其中同一函数应满足用例add(2)(3)(4)和/ add(2,3,4)或任何组合。因此,单个函数应满足以下情况,

  • 添加(2)(3)(4)
  • 添加(2,3,4)
  • 添加(2)(3,4)
  • 添加(2,3)(4)

对于这种类型,让我们考虑固定的’n’个参数(在我们的例子中,n = 3)。如果我们需要使用可变数量的参数来实现这一点,我们可以通过上述问题的解决方案来解决这些问题。这里的技巧是跟踪’n’个参数,一旦我们有足够数量的参数,我们就会返回总和。

1.使用arguments计数的解决方案

以下代码保持传递的总参数计数,如果它达到3,则给出结果总和

function add(){
    let args = [].slice.apply(arguments);
    function resultFn(){
        args = args.concat([].slice.apply(arguments));
        if(args.length>=3){
            return args.slice(0,3).reduce(function(acc,next){ return acc+next},0); //will only sum first 3 arguments
        }
        return resultFn;
    }
    return resultFn();
}

样品用法,

> add(2)(3)(4) //output: 9
> add(2,3,4) //output: 9
> add(2)(3,4) //output: 9
> add(2,3)(4) //output: 9
2.固定参数函数的通用解决方案

这里的方法是创建一个更高阶的函数,它将获取该函数必须的函数和参数数量 - 在我们的例子中为add(2,3,4)。除非总收集的参数与传递函数的预期参数相同,否则此函数将跟踪参数。

function fixCurry(fn, totalArgs){
    totalArgs = totalArgs ||fn.length
        return function recursor(){
            return arguments.length<totalArgs?recursor.bind(this, ...arguments): fn.call(this, ...arguments);
        }
}

上面的函数接受一个函数 - fn并且可选地totalArgs在调用之前是必需的fn。如果totalArgs没有传递,它将依赖于函数签名并使用属性fn.length,该属性是已定义函数的参数个数。 totalArgs可用于函数 - fn其实现本身依赖arguments于其签名中未定义参数。 fixCurry返回一个不断向函数添加(通过bind)参数的函数,如果达到阈值,它只调用所有调用之间收集的所有参数的函数。

让我们看看样品的用法,

> var add = fixCurry((a,b,c)=>a+b+c); //fn = summation function
> console.log(add(1,2, 3))  // output: 6
> console.log(add(1)(2,3)) // output: 6
> console.log(add(1)(3)(2)) // output: 6
> console.log(add(1,2)(3)) // output: 6

同样适用于乘法(或任何其他curried函数),

> var multiply = fixCurry((a,b,c)=>a*b*c); //fn = multiplication function
> console.log(multiply(1,2, 3))  // output: 6
> console.log(multiply(1)(2,3)) // output: 6
> console.log(multiply(1)(3)(2)) // output: 6
> console.log(multiply(1,2)(3)) // output: 6

fixCurry也可以用于使用固定参数来调整任何函数。

与另一个要注意addmultiply例子是,前3个自然数的加法和乘法是相同的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值