在JavaScript中关闭 - 什么是错的?

时间:2013-08-05 19:39:04

标签: javascript closures

我试图通过闭包制作下一个:

function func(number) {
    var result = number;

    var res = function(num) {
        return result + num;
    };
    return res;
}

var result = func(2)(3)(4)(5)(3);
console.log(result); // 17

我需要收到2 + 3 + 4 + 5 + 3 = 17 但我得到一个错误:未捕获TypeError:数字不是函数

7 个答案:

答案 0 :(得分:8)

你误用了你的功能。

func(2)会返回res函数 使用(3)调用该函数会返回数字5(通过return result + num)。

5不是函数,因此(4)会出错。

答案 1 :(得分:8)

您必须以某种方式表示链的末尾,您将返回结果编号而不是其他函数。您可以选择:

  • 让它返回一个固定次数的函数 - 这是使用语法的唯一方法,就像你拥有它一样,但它很无聊。看看@PaulS的回答。您可以进行第一次调用(func(n)),以提供sum curried个参数的数量。
  • 在某些情况下返回结果,例如在没有参数的情况下调用函数(@PaulS'第二个实现)或在@ AmoghTalpallikar的答案中使用特殊值(null)。
  • 在函数对象上创建一个返回值的方法。 valueOf()非常适合,因为当函数转换为原始值时将调用它。看到它在行动:

    function func(x) {
        function ret(y) {
            return func(x+y);
        }
        ret.valueOf = function() {
            return x;
        };
        return ret;
    }
    
    func(2) // Function
    func(2).valueOf() // 2
    func(2)(3) // Function
    func(2)(3).valueOf() // 5
    func(2)(3)(4)(5)(3) // Function
    func(2)(3)(4)(5)(3)+0 // 17
    

答案 2 :(得分:3)

嗯,(2)(3)部分是正确的。调用func(2)将返回res,这是一个函数。但是,调用(3)将返回res的结果,这是一个数字。所以当你试着打电话给(4)时会出现问题。

对于你想要做的事情,我没有看到Javascript如何预测你是在链的末尾,并决定返回一个数字而不是一个函数。也许你可以使用对象属性以某种方式返回具有“结果”属性的函数,但大多数情况下我只是好奇你为什么要这样做。显然,对于你的具体例子,最简单的方法就是将数字加在一起,但我猜你会更进一步。

答案 3 :(得分:0)

如果你想继续调用它,你需要继续返回一个函数,直到你想要你的答案。例如5次调用

function func(number) {
    var result = number,
        iteration = 0,
        fn = function (num) {
            result += num;
            if (++iteration < 4) return fn;
            return result;
        };
    return fn;
}
func(2)(3)(4)(5)(3); // 17

你也可以做更多长度的事情,就像这样

function func(number) {
    var result = number,
        fn = function () {
            var i;
            for (i = 0; i < arguments.length; ++i)
                result += arguments[i];
            if (i !== 0) return fn;
            return result;
        };
    return fn;
}
func(2)(3, 4, 5)(3)(); // 17

答案 4 :(得分:0)

我将此标记为重复,但由于此问题中也缺少此选项,我将在此处添加。如果我理解正确为什么你会认为这很有趣(有一个任意函数顺序应用于值列表,累积结果),你还应该研究reduce

function sum(a, b) {
    return a + b;
}

a = [2, 3, 4, 5, 3];

b = a.reduce(sum);

答案 5 :(得分:0)

另一个解决办法可能就是调用没有参数的函数来获得结果,但如果用params调用它就会增加总和。

function add() {
  var sum = 0;
  var closure = function() {
    sum = Array.prototype.slice.call(arguments).reduce(function(total, num) {
      return total + num;
    }, sum);
    return arguments.length ? closure : sum;
  };
  return closure.apply(null, arguments);
}

console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)); //  function(){}
console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)()); // 30;

答案 6 :(得分:0)

我们可以使用几个辅助函数identitysumk轻松完成它。

sumk使用延续来保留挂起的 add 计算的堆栈,并在调用第一个0时用()展开堆栈。

const identity = x => x

const sumk = (x,k) =>
  x === undefined ? k(0) : y => sumk(y, next => k(x + next))

const sum = x => sumk(x, identity)

console.log(sum())                // 0
console.log(sum(1)())             // 1
console.log(sum(1)(2)())          // 3
console.log(sum(1)(2)(3)())       // 6
console.log(sum(1)(2)(3)(4)())    // 10
console.log(sum(1)(2)(3)(4)(5)()) // 15