Encerramento em JavaScript – o que está errado?

Eu tentando fazer o próximo com o fechamento:

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 

Preciso receber 2 + 3 + 4 + 5 + 3 = 17 Mas recebi um erro: Uncaught TypeError: number não é uma function

Você está abusando de suas funções.

func(2) retorna a function res .
Chamar essa function com (3) retorna o número 5 (via return result + num ).

5 não é uma function, então (4) dá um erro.

Você de alguma forma tem que sinalizar o final da cadeia, onde você irá retornar o número do resultado ao invés de outra function. Você tem a escolha:

  • faça com que retorne uma function por um número fixo de vezes – esta é a única maneira de usar a syntax como você a possui, mas é chata. Veja a resposta do @PaulS para isso. Você pode fazer a primeira chamada ( func(n) ) fornecer o número de quantos argumentos a sum é curried .
  • retorna o resultado sob certas circunstâncias, como quando a function é chamada sem argumentos (segunda implementação do @PaulS) ou com um valor especial ( null na resposta do @ AmoghTalpallikar).
  • crie um método no object de function que retorna o valor. valueOf() é adequado também porque será invocado quando a function for convertida em um valor primitivo. Veja em ação:

     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 

Bem, a parte (2) (3) está correta. Chamar func (2) vai retornar sua res , que é uma function. Mas então, chamar (3) vai retornar o resultado da res , que é um número. Então o problema surge quando você tenta ligar (4).

Para o que você está tentando fazer, não vejo como o JavaScript poderia prever que você está no final da cadeia e decidir retornar um número em vez de uma function. Talvez você possa de alguma forma retornar uma function que tenha uma propriedade “result” usando propriedades de object, mas na maioria das vezes estou apenas curioso sobre por que você está tentando fazer as coisas dessa maneira. Obviamente, para o seu exemplo específico, a maneira mais fácil seria apenas adicionar os números juntos, mas eu acho que você está indo um pouco mais longe com alguma coisa.

Eu sinalizei isso como uma duplicata, mas como essa alternativa também está faltando nessa questão, adicionarei aqui. Se eu entendi corretamente porque você acha que isso é interessante (ter uma function arbitrária que é aplicada sequencialmente a uma lista de valores, acumulando o resultado), você também deve procurar reduce :

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

Outra solução poderia ser apenas chamar a function sem params para obter o resultado, mas se você a chamar com params, ela será adicionada à 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; 

Eu posso fazer trabalho claro disto usando um par de funções de ajudante identity e sumk .

sumk usa uma continuação para manter uma pilha dos cálculos de adição pendentes e desenrola a pilha com 0 sempre que o primeiro () é chamado.

 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 

Se você quiser continuar invocando, você precisa continuar retornando uma function até que você queira sua resposta. por exemplo, para 5 invocações

 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 

Você também pode fazer algo por mais comprimentos que funcione assim

 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