问题
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
回答1:
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.
回答2:
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 argumentssum
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
回答3:
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.
回答4:
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
回答5:
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);
回答6:
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;
回答7:
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
来源:https://stackoverflow.com/questions/18066322/closure-in-javascript-whats-wrong