Cierre en JavaScript – ¿Cuál es el problema?

Estoy tratando de hacer luego con el cierre:

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 

Necesito recibir 2 + 3 + 4 + 5 + 3 = 17 Pero recibí un error: UnEught TypeError: number no es una función

Estás haciendo un uso indebido de tus funciones.

func(2) devuelve la función res .
Llamar a esa función con (3) devuelve el número 5 (a través del return result + num ).

5 no es una función, entonces (4) da un error.

De alguna manera tiene que indicar el final de la cadena, donde va a devolver el número de resultado en lugar de otra función. Usted tiene la opción:

  • hacer que devuelva una función por un número fijo de veces; esta es la única manera de usar la syntax como la tiene, pero es aburrido. Mire la respuesta de @PaulS para eso. Puede hacer que la primera invocación ( func(n) ) proporcione el número de cuántos argumentos se curry .
  • devuelve el resultado bajo ciertas circunstancias, como cuando se llama a la función sin argumentos (segunda implementación de @PaulS) o con un valor especial ( null en la respuesta de @ AmoghTalpallikar).
  • crea un método en el objeto de función que devuelve el valor. valueOf() se adapta bien porque se invocará cuando la función se transfiera a un valor primitivo. Véalo en acción:

     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 

Bueno, la parte (2) (3) es correcta. Llamar func (2) te devolverá res , que es una función. Pero luego, llamar (3) te devolverá el resultado de res , que es un número. Entonces, el problema surge cuando intentas llamar (4).

Por lo que estás tratando de hacer, no veo cómo Javascript predeciría que estás al final de la cadena, y decides devolver un número en lugar de una función. Tal vez de alguna manera podría devolver una función que tiene una propiedad de “resultado” usando propiedades de objeto, pero sobre todo tengo curiosidad acerca de por qué está tratando de hacer las cosas de esta manera. Obviamente, para su ejemplo específico, la manera más fácil sería simplemente sumr los números, pero supongo que va un poco más allá con algo.

Marqué esto como un duplicado, pero como esta alternativa también falta en esa pregunta, la agregaré aquí. Si entiendo correctamente por qué pensaría que esto es interesante (teniendo una función arbitraria que se aplica secuencialmente a una lista de valores, acumulando el resultado), también debe considerar reduce :

 function sum(a, b) { return a + b; } a = [2, 3, 4, 5, 3]; b = a.reduce(sum); 

Otra solución podría ser simplemente llamar a la función sin params para obtener el resultado, pero si lo llamas con params, se sum a la 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; 

Podemos hacer un trabajo ligero con un par de funciones auxiliares, identity y sumk .

sumk usa una continuación para mantener una stack de los cómputos de adición pendientes y desenrolla la stack con 0 cada vez que se llama al primer () .

 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 

Si desea seguir invocándolo, debe continuar devolviendo una función hasta que desee su respuesta. por ejemplo, para 5 invocaciones

 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 

También puedes hacer algo por más longitudes que funcione así

 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