Multiplicando funções… Ou números executáveis?

Erich Oliveira
2 min readAug 31, 2015

No último post, eu falei um pouco sobre memoization e para isso, mostrei como utilizar propriedades em funções, no post de hoje, eu vou mostrar algo um pouco bizarro, um objeto que pode se comportar como função ou como número dependendo da necessidade em javascript.

O exemplo que vou mostrar é o seguinte, vamos criar um função de somatório onde eu possa ir somando números indefinidamente a cada execução, a qualquer momento, eu posso parar de executá-la e utilizar qualquer operador aritmético (soma, subtração e etc), como no exemplo abaixo:

somatorio(0)(2)(3)(5) + 10 === 20

Note que para completar o desafio essa função tem que poder ser chamada quantas vezes eu quiser, ou seja, também pode ser chamada assim:

somatorio(3) + 7 === 10

Ou até:

somatorio + 5 === 5

E como eu disse que ela iria se comportar como número, também deve aceitar:

somatorio(2)(3) * 5 === 25

Alguma ideia???

Vamos a primeira parte, fazer um função que some números indefinidamente é muito fácil:

var somatorio = function(n){
if(somatorio.acumulador==null){
somatorio.acumulador = 0;//Lembrem do último post
}
somatorio.acumulador += n;
return somatorio;
};

Temos acima, uma função que guarda no atributo acumulador dela mesma o resultado das somas, o retorno dela é ela mesma, assim posso ficar somando valores indefinidamente o resultado das operações estará disponível em somatorio.acumulador

Interessante, mas não foi isso que prometi, o meu código inicial é:

somatorio(0)(2)(3)(5) + 10 === 20

E com o que foi demonstrado até agora o máximo que consigo fazer é:

somatorio(0)(2)(3)(5) 
somatorio.acumulador + 10 === 20

O que é péssimo…

Antes de mostrar a solução completa, é preciso entender o que o javascript faz quando ele lê "somatorio(0)(2)(3)(5) + 10" , lembre-se somatorio é uma função que sempre retorna uma função o que estou fazendo ali em cima é basicamente "function(){} + 10" . É preciso entender que o operador + (assim como * % / -…) são atribuidos a tipos primitivos, quando o interpretador do js lê a expressão “function(){} + 10” ele tenta transformar essa função em um primitivo (ele faz isso com qualquer objeto, não só funções), e ele faz isso, executando a função valueOf do objeto, logo, podemos modificar essa função para fazer com que ela retorne "somatorio.acumulador" , e isso é muito fácil.

somatorio.valueOf=function(){
return somatorio.acumulador;
};

Simples…

O código completo fica:

var somatorio = function(n){
if(somatorio.acumulador==null){
somatorio.acumulador = 0;//Lembrem do último post
}
somatorio.acumulador += n;
return somatorio;
};
somatorio.valueOf=function(){
return somatorio.acumulador;
};

E você pode testar na console do chrome ou no node, tudo o que coloquei ali em cima:

somatorio(0)(2)(3)(5) + 10; //20

Ps: Lembre-se que a função é um acumulador, chamá-la diversas vezes seguidas acumulará os valores, para torná-la idempotente, você poderia ir retornando sempre uma nova função, mas esse não é o escopo dessa postagem.

Ps2: O código é real, funciona, mas é só uma brincadeira, para ajudar a expandir o conhecimento, não é recomendado escrever isso no sistema da empresa que você trabalha, porque ninguém vai entender nada.

--

--