Entendendo Higher Order Functions no Javascript
Higher Order Function é um conceito muito básico (e também muito importante) mas também um pouco incompreendido por alguns.
Vamos primeiramente entender o conceito, a definição mais clara, simples e direta que você provavelmente poderá utilizar em alguma entrevista técnica.
O que são as Higher Order Functions? (aka HOF).
Higher Order Function é toda função que aceita uma função como parâmetro e/ou retorna uma função.
Antes de partirmos para uma explicação mais aprofundada, cabe listarmos algumas das importâncias das HOFs na programação.
- Torna o nosso código mais declarativo e de fácil leitura.
- É o conceito chave para conceitos mais complexos da programação, como closures, currying, promises, etc.
- Conseguimos generalizar funções para que possamos reutiliza-las de maneiras diferentes quando necessário.
Entendendo as HOFs.
Veja o código abaixo:
function copyArrayAndMultiplyBy5(array) {
const output = [];
for (let i = 0; i < array.length; i++) {
output.push(array[i] * 5);
}
return output;
}
const myArray = [1,2,3];
const result = copyArrayAndMultiplyBy5(myArray);
Suponha que quiséssemos fazer agora uma função de multiplicação por 3, 4. Ou talvez de adição, ou divisão. Teríamos que copiar e colar várias funções, mudando apenas o nome e os valores de 5 para 3, 4 e também os operadores de * para + e /.
E se, ao invés de definirmos no momento que declaramos a nossa função esse comportamento, pudéssemos definir um parâmetro para receber uma função como argumento e deixar o comportamento para o momento que a executarmos?
No Javascript funções são objetos, chamadas de objetos de primeira classe.
Se podemos passar objetos como argumentos para uma função, logo podemos passar uma função também.
Vamos então fazer uma alteração no nosso código.
function copyArrayAndManipulate(array, fn) {
const output = [];
for (let i = 0; i < array.length; i++) {
output.push(fn(array[i]));
}
return output;
}
Veja que agora criamos uma função genérica, copyArrayAndManipulate, que recebe como parâmetro o array e uma função fn.
Não sabemos todo o comportamento que essa função terá no momento de sua declaração, e não precisamos saber.
A função copyArrayAndManipulate é a nossa Higher Order Function, enquanto a função fn que passaremos mais adiante por argumento é a nossa função de callback.
Agora podemos criar as nossas variações de uma maneira muito mais fácil e dinâmica, sem termos que ficar copiando e colando código.
function copyArrayAndManipulate(array, fn) {
const output = [];
for (let i = 0; i < array.length; i++) {
output.push(fn(array[i]));
}
return output;
}
function multiplyBy5(input) {
return input * 5;
}
function multiplyBy3(input) {
return input * 3;
}
function multiplyBy4(input) {
return input * 4;
}
const result1 = copyArrayAndManipulate([1, 2, 3], multiplyBy5);
const result2 = copyArrayAndManipulate([1, 2, 3], multiplyBy3);
const result3 = copyArrayAndManipulate([1, 2, 3], multiplyBy4);
Nosso código ficou muito mais declarativo e legível, pois na leitura sabemos exatamente que o valor de result1 será a cópia do array [1, 2, 3] multiplicada por 5, por exemplo.
Beleza, isso já melhorou bastante a escrita do nosso código evitando código desnecessário, mas podemos deixar a estética ainda melhor com as arrow functions.
function copyArrayAndManipulate(array, fn) {
const output = [];
for (let i = 0; i < array.length; i++) {
output.push(fn(array[i]));
}
return output;
}
const multiplyBy5 = (input) => input * 5;
const multiplyBy3 = (input) => input * 3;
const multiplyBy4 = (input) => input * 4;
const result1 = copyArrayAndManipulate([1, 2, 3], multiplyBy5);
const result2 = copyArrayAndManipulate([1, 2, 3], multiplyBy3);
const result3 = copyArrayAndManipulate([1, 2, 3], multiplyBy4);
Muito melhor. Mas não precisamos guardar as nossas funções em uma constante, podemos passar as funções diretamente, isso também nos dará mais dinamismo.
function copyArrayAndManipulate(array, fn) {
const output = [];
for (let i = 0; i < array.length; i++) {
output.push(fn(array[i]));
}
return output;
}
const result1 = copyArrayAndManipulate([1, 2],(input) => input * 5);
const result2 = copyArrayAndManipulate([1, 2],(input) => input * 3);
const result3 = copyArrayAndManipulate([1, 2],(input) => input * 4);
Os mais atentos já devem ter percebido uma similaridade com a função map, que sim, é exatamente como ela funciona. E assim como a map temos outras funções muito utilizadas e conhecidas que são HOFs (como filter e reduce).
Conclusão
Higher Order Function é um conceito simples e importante, porém muitas pessoas tem um pouco de dificuldade de entender o que é.
Espero ter conseguido desmistificar isso da melhor maneira possível.
Até a próxima. 😃 👋
Veja também:
Entendendo closures no Javascript
Entendendo Classes e Prototype no Javascript
Meu website pessoal