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
阅读 12.1k
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);

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

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

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

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

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

具体可以看看这个实现curry

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

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

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

    func.toString = func.valueOf = function() {
        return temp;
    };

    return func;
}

首先,完全按照题目实现,根本实现不了,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)());
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏