当前位置: 动力学知识库 > 问答 > 编程问答 >

Closure in JavaScript - whats wrong?

问题描述:

I trying to make next with closure:

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

I need to receive 2 + 3 + 4 + 5 + 3 = 17

But I got an error: Uncaught TypeError: number is not a function

网友答案:

You're misusing your functions.

func(2) returns the res function.
Calling that function with (3) returns the number 5 (via return result + num).

5 is not a function, so (4) gives an error.

网友答案:

You somehow have to signalize the end of the chain, where you are going to return the result number instead of another function. You have the choice:

  • make it return a function for a fixed number of times - this is the only way to use the syntax like you have it, but it's boring. Look at @PaulS' answer for that. You might make the first invocation (func(n)) provide the number for how many arguments sum is curried.
  • return the result under certain circumstances, like when the function is called with no arguments (@PaulS' second implementation) or with a special value (null in @AmoghTalpallikar's answer).
  • create a method on the function object that returns the value. valueOf() is suited well because it will be invoked when the function is casted to a primitive value. See it in action:

    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
    
网友答案:

Well, the (2)(3) part is correct. Calling func(2) is going to return you res, which is a function. But then, calling (3) is going to return you the result of res, which is a number. So the problem comes when you try to call (4).

For what you're trying to do, I don't see how Javascript would predict that you're at the end of the chain, and decide to return a number instead of a function. Maybe you could somehow return a function that has a "result" property using object properties, but mostly I'm just curious about why you're trying to do things this way. Obviously, for your specific example, the easiest way would just be adding the numbers together, but I'm guessing you're going a bit further with something.

网友答案:

I flagged this as a duplicate, but since this alternative is also missing from that question I'll add it here. If I understand correctly why you would think this is interesting (having an arbitrary function that is applied sequentially to a list of values, accumulating the result), you should also look into reduce:

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

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

b = a.reduce(sum);
网友答案:

Another solution could be just calling the function without params in order to get the result but if you call it with params it adds to the sum.

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;
网友答案:

We can make light work of it using a couple helper functions identity and sumk.

sumk uses a continuation to keep a stack of the pending add computations and unwinds the stack with 0 whenever the first () is called.

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
网友答案:

If you want to keep invoking it, you need to keep returning a function until you want your answer. e.g. for 5 invocations

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

You could also do something for more lengths that works like this

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
分享给朋友:
您可能感兴趣的文章:
随机阅读: