登录

currying - Javascript 连续调用单参函数实现任意参函数

函数 add 可以实现连续的加法运算
函数 add 语法如下 add(num1)(num2)(num3)...; //注意这里是省略号哟,可无限

使用举例如下:

add(10)(10); // 20
add(10)(20)(50); // 80
add(10)(20)(50)(100); // 180

var add30 = add(10)(20); // 30
var add100 = add30(30)(40); // 100
var add31 = add30(1); // 31
var add40 = add31(9); // 40
# JavaScript
天蓬老师天蓬老师2178 天前1012 次浏览

全部回复(14) 我要回复

  • PHP中文网

    PHP中文网2017-04-10 15:30:14

    @bf 老师的答案非常棒,学习了。不过我想@bf 老师实际上还是搞反了 currying 和 uncurrying。
    currying 是将参数提前保存以在下一次调用时不必提供此参数,@bf 老师的代码所做的正是这个工作。而 uncurrying 则是将原来设定好的参数腾出来,使之可以被函数调用者重新设定。在 JavaScript 中常用于将 obj.func(x, y, z, ...)转变为 func(org, x, y, z)。这样做的好处是可以方便地应用 Duck Type
    这种特性。@bf 老师后面提供的 curry 代码其实才是真正的 uncurry。(@bf 菜菜已經將自己的答案 reverse 到 r4,which fits the en wikipedia)

    另,
    如下代码也可以很好的工作(其实还是一种 currying,将每次的和绑定到下次调用,这样就可以连加了):

    function add(x) {
        function helper(y, x) {
            var sum = y + x;
            var f = helper.bind(null, sum);
            f.toString = function () {
                return '' + sum;
            };
            f.valueOf = function () {
                return sum;
            };
            return f;
        }
        return helper(x, 0);
    }
    console.log(+add(10)(10)); // 20
    console.log(+add(10)(20)(50)); // 80
    console.log(+add(10)(20)(50)(100)); // 180
    
    var add30 = add(10)(20); // 30
    var add100 = add30(30)(40); // 100
    var add31 = add30(1); // 31
    var add40 = add31(9); // 40
    
    console.log(+add30, +add100, +add31, +add40);
    

    实际上就是要把每一次函数调用的结果都区分开而已。

    回复
    0
  • 迷茫

    迷茫2017-04-10 15:30:14

    javascriptfunction add(a){
        function x(b){
            a+=b;
            return x;
        }
        x.toString=function(){return a;}
        return x;
    }
    console.log(
        add(10)(10) == 20 &&
        add(10)(20)(50) == 80 &&
        add(10)(20)(50)(100) == 180
    );// true
    

    返回一个返回自身的函数,就可以做到无限调用。

    回复
    0
  • 黄舟

    黄舟2017-04-10 15:30:14

    reversed to r4; nonsense was deleted.

    這道題考得是柯里化。

    function curry(fn) {
        return function(x) {
            return function g(x, y) {
                if (y === void 0)
                    return x;
                else
                    return g.bind(this, fn(x, y));
            }.bind(this, x);
        };
    }
    
    function add(x, y) {
        return x + y;
    }
    
    var curried_add = curry(add); 
    
    curried_add(1)(2)(); // 3
    curried_add(1)(2)(3)(); // 6
    curried_add(1)(2)(3)(); // 6
    curried_add(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)(16)(17)(18)(19)(20)(); // 210
    
    
    var a1 = curried_add(1);
    
    var a2 = a1(2);
    var a3 = a1(3);
    
    var a4 = a3(4);
    
    a1(), a2(), a3(), a4(); // 1 3 4 8
    

    回复
    0
  • 阿神

    阿神2017-04-10 15:30:14

    这个问题叫做柯里化(curry),不是勇士的库里。柯里化就是预先将函数的某些参数传入,得到一个简单的函数,但是预先传入的参数被保存在闭包中。

    具体可以看看这个实现curry

    回复
    0
  • 高洛峰

    高洛峰2017-04-10 15:30:14

    var add = function () {
      var args = [].slice.call(arguments),
          count = 0;
    
     args.forEach(function (value) {
        count += value;
      });
    
      return function () {
        var args = [].slice.call(arguments);
    
        if (!args.length) {return count;}
    
        args.unshift(count);
    
        return add.apply(null, args);
      };
    };
    
    还可以这样调用:
    var add30 = add(10, 10, 10);
    也可以这样调用:
    var add30 = add(10)(10)(10);
    
    var add100 = add30(20)(20)(30);
    add100();    //100
    

    回复
    0
  • PHP中文网

    PHP中文网2017-04-10 15:30:14

    我没记错的话这个是这题吧,原题应该是 CodeWar 上的。

    jsfunction add(n) {
        var temp = n;
        var func = function(n) {
            temp += n;
            return func;
        };
    
        func.toString = func.valueOf = function() {
            return temp;
        };
    
        return func;
    }
    

    回复
    0
  • 大家讲道理

    大家讲道理2017-04-10 15:30:14

    首先,完全按照题目实现,根本实现不了,add(1)(2)如果返回3,add(1)(2)(3)必然报错。

    我们退一步,实现add(1)(2)()返回3,add(1)(2)(3)()返回6。

    有两种方法,第一种是每次调用都计算出中间结果,最后无参数调用时把结果返回,另一种是把加数都记下来,无参数调用时执行加法并返回。

    第一种:

    function add(a) {
        if (typeof a === 'undefined') {
            return 0;
        }
    
        function add_(a, b) {
            var s = a + b;
    
            return function (c) {
                if (typeof c === 'undefined') {
                    return s;
                }
    
                return add_(s, c);
            }
        }
    
        return add_(0, a);
    }
    
    console.log(add());
    console.log(add(1)(2)());
    console.log(add(1)(2)(3)());
    

    第二种:

    function add(a) {
        if (typeof a === 'undefined') {
            return 0;
        }
    
        if (typeof a !== 'number') {
            var sum = 0;
    
            for (var i = 0; i < a.length; ++i) {
                sum += a[i];
            }
    
            return sum;
        }
    
        var args = Array.prototype.slice.call(arguments, 0);
    
        return function (b) {
            if (typeof b === 'undefined') {
                return add(args);
            }
    
            args.push(b);
    
            return add.apply(this, args);
        }
    }
    
    console.log(add());
    console.log(add(1)(2)());
    console.log(add(1)(2)(3)());
    

    回复
    0
  • 巴扎黑

    巴扎黑2017-04-10 15:30:14

    php
    function add(x){ var sum=x; var tmp=function(y){ sum+=y; return tmp; }; tmp.toString=function(){ return sum; }; return tmp; } console.log(add(1)(2)(3));//6 console.log(add(1)(2)(3)(4)(5));//15

    回复
    0
  • 巴扎黑

    巴扎黑2017-04-10 15:30:14

    问他想考你什么
    如果想考闭包,和函数式,和原型继承那就写给他,如果他不说
    那么直接写个window.sum=0和function add()气死他

    那么,就写个靠谱(~~并不靠谱,看楼上们)点的答案吧

    1.首先需要优雅点的写法,不写成window.var,所以写个闭包

    function foo(){
    var bar=function(){}
    }
    

    2.然后思考一下函数式累加怎么写,第一步当然是 sum=0+input;

    function foo(x){
    x=0+x;
    var bar=function(){};
    }
    

    3.这时,得把x扔进子作用域bar才行,不然就记不住这个sum了.然后进一步的累加就交由bar来处理了,理由同上.

    function foo(x){
    x=0+x;
    var bar=function(y){
    x=x+y;
    };
    }
    

    4.再把整个结构贯通一下,先运行foo,获得result,交由bar,并且return出bar,return bar后才能继续走下一步
    //我发现这里好像是markdown??

    function foo(x){
    x=0+x;
    var bar=function(y){
    x=x+y;
    };
    return bar;
    }
    

    5.好了,现在到bar了,这就比较简单了,不用考虑闭包这无聊的事,sum_new=sum_odd + input;接着呢 还要继续累加那么,直接无限调用自身就好了,所以bar:return bar;

    function foo(x){
    x=0+x;
    var bar=function(y){
    x=x+y;
    return bar;
    };
    return bar;
    }
    

    6.其实已经完事了,只不过为了应付原型继承这个考点,还要蛋疼的多写一步.这个也是很赖皮的..我就不想写了,反正上面代码都有了.所以我show我喜欢的写法

    function foo(x){
    x=0+x;
    var bar=function(y){
    x=x+y;
    return bar;
    };
    bar.show=function(){console.log(x);}
    return bar;
    }
    

    result :foo(1)(2)(3).show() = 6

    回复
    0
  • 大家讲道理

    大家讲道理2017-04-10 15:30:14

    function add(num) {
        var sum = 0;
    
        function cache(arg) {
            if (arg === undefined) {
                return sum;
            } else {
                sum += arg;
            }
    
            return cache
        }
    
    
        return cache(num);
    }
    
    console.log(add(1)(2)());
    console.log(add(1)(2)(4)(5)());
    

    唯一的缺点,最后结束时必须再次调用一次。
    哪位大神来完善下

    回复
    0
  • 取消回复发送