Funções de ordem superior
Esta aula explora funções de ordem superior em JavaScript, mostrando como funções podem ser tratadas como valores, passadas como callbacks e retornadas por outras funções. O conteúdo inclui exemplos práticos, boas práticas e exercícios com respostas ocultas.
Funções de ordem superior são um conceito fundamental em JavaScript, permitindo que funções sejam tratadas como cidadãos de primeira classe. Isso significa que podemos atribuir funções a variáveis, passá-las como argumentos para outras funções e até mesmo retorná-las de outras funções. Esse paradigma é a base para padrões como callbacks, programação funcional e muitas APIs modernas, como métodos de array (map, filter, reduce).
Nesta aula, vamos explorar três aspectos essenciais: funções como valores, callbacks e retorno de funções. Você entenderá como esses conceitos se conectam e como aplicá-los no dia a dia para escrever código mais flexível e reutilizável.
Funções como valores
Em JavaScript, funções são objetos de primeira classe, o que significa que podem ser armazenadas em variáveis, propriedades de objetos, arrays e passadas como argumentos. Isso permite que você trate um bloco de código como um dado manipulável.
Por exemplo, você pode definir uma função anônima e atribuí-la a uma variável:
const saudacao = function(nome) {
return `Olá, ${nome}!`;
};
console.log(saudacao('Maria')); // Olá, Maria!Também é possível atribuir funções a propriedades de objetos ou colocá-las em arrays:
const operacoes = {
soma: (a, b) => a + b,
subtracao: (a, b) => a - b
};
console.log(operacoes.soma(5, 3)); // 8
const listaDeFuncoes = [
x => x * 2,
x => x + 1
];
console.log(listaDeFuncoes[0](10)); // 20Essa capacidade de tratar funções como valores é o que possibilita o uso de funções de ordem superior.
Callbacks
Um callback é uma função passada como argumento para outra função, que será executada em um momento posterior, geralmente após a conclusão de uma operação assíncrona ou para personalizar o comportamento de uma função.
Um exemplo clássico é o método forEach de arrays, que recebe uma função callback para ser executada para cada elemento:
const numeros = [1, 2, 3];
numeros.forEach(function(numero) {
console.log(numero * 2);
});
// Saída: 2, 4, 6Você também pode criar suas próprias funções que aceitam callbacks. Por exemplo, uma função que executa uma operação em cada elemento de um array e retorna um novo array:
function transformar(array, callback) {
const resultado = [];
for (let i = 0; i < array.length; i++) {
resultado.push(callback(array[i], i, array));
}
return resultado;
}
const dobrados = transformar([1, 2, 3], (num) => num * 2);
console.log(dobrados); // [2, 4, 6]Callbacks são essenciais para programação assíncrona, como em requisições AJAX, leitura de arquivos e temporizadores:
setTimeout(() => {
console.log('Executado após 1 segundo');
}, 1000);No entanto, o uso excessivo de callbacks pode levar ao "callback hell". Para mitigar isso, JavaScript oferece Promises e async/await, mas o conceito de callback continua sendo fundamental.
Retornando funções
Uma função pode retornar outra função, criando closures e permitindo a criação de funções especializadas ou fábricas de funções. Isso é útil para criar funções com comportamento configurável.
Exemplo simples: uma função que retorna um saudador personalizado:
function criarSaudador(saudacao) {
return function(nome) {
console.log(`${saudacao}, ${nome}!`);
};
}
const saudarOla = criarSaudador('Olá');
saudarOla('João'); // Olá, João!
const saudarOi = criarSaudador('Oi');
saudarOi('Maria'); // Oi, Maria!Outro exemplo clássico é a função bind ou a criação de funções com argumentos pré-preenchidos (currying):
function multiplicar(a) {
return function(b) {
return a * b;
};
}
const dobrar = multiplicar(2);
console.log(dobrar(5)); // 10
const triplicar = multiplicar(3);
console.log(triplicar(5)); // 15Essa técnica é amplamente utilizada em bibliotecas como React (hooks personalizados) e Redux (middleware).
Boas práticas e observações finais
Ao trabalhar com funções de ordem superior, lembre-se de:
- Usar nomes descritivos para callbacks e funções retornadas.
- Evitar callbacks aninhados profundamente; prefira Promises ou async/await.
- Documentar o tipo de callback esperado (parâmetros e retorno).
- Tomar cuidado com o escopo e o valor de
this; use arrow functions quando apropriado. - Testar funções de ordem superior com diferentes entradas para garantir robustez.
Funções de ordem superior são uma ferramenta poderosa que torna o código mais expressivo e modular. Dominá-las é essencial para se tornar um desenvolvedor JavaScript proficiente.
Referências
- MDN: Funções (Guia JavaScript)
- MDN: Array.prototype.forEach()
- MDN: Closures
- MDN: Function.prototype.bind()
- JavaScript.info: Function expressions
- freeCodeCamp: Higher Order Functions in JavaScript
Exercícios
Crie uma função de ordem superior chamada
executarVariasVezesque recebe uma funçãofne um númeron, e executafnnvezes. Teste com uma função que imprime "Olá".✓ Resposta:function executarVariasVezes(fn, n) { for (let i = 0; i < n; i++) { fn(); } } executarVariasVezes(() => console.log('Olá'), 3); // Olá (3 vezes)Implemente uma função
filtrarque recebe um array e uma função callback de teste, e retorna um novo array apenas com os elementos que passam no teste. Não usefilternativo.✓ Resposta:function filtrar(array, callback) { const resultado = []; for (let i = 0; i < array.length; i++) { if (callback(array[i], i, array)) { resultado.push(array[i]); } } return resultado; } const numeros = [1, 2, 3, 4, 5]; const pares = filtrar(numeros, num => num % 2 === 0); console.log(pares); // [2, 4]Crie uma função
comporque recebe duas funçõesfege retorna uma nova função que aplicaga um argumento e depoisfao resultado. Por exemplo,compor(x => x * 2, x => x + 1)(5)deve retornar 12.✓ Resposta:function compor(f, g) { return function(x) { return f(g(x)); }; } const multiplicarPor2 = x => x * 2; const somar1 = x => x + 1; const funcaoComposta = compor(multiplicarPor2, somar1); console.log(funcaoComposta(5)); // 12 (primeiro soma 1, depois multiplica por 2)Escreva uma função
criarContadorque retorna um objeto com dois métodos:incrementarevalor. O contador deve começar em 0 e ser privado (usando closure).✓ Resposta:function criarContador() { let contador = 0; return { incrementar: function() { contador++; }, valor: function() { return contador; } }; } const meuContador = criarContador(); meuContador.incrementar(); meuContador.incrementar(); console.log(meuContador.valor()); // 2Implemente uma função
mapAsyncque recebe um array e uma função callback assíncrona (que retorna uma Promise) e retorna uma Promise que resolve com um array dos resultados. UsePromise.all.✓ Resposta:function mapAsync(array, callback) { return Promise.all(array.map(callback)); } // Exemplo: const numeros = [1, 2, 3]; const asyncDobrar = (num) => Promise.resolve(num * 2); mapAsync(numeros, asyncDobrar).then(resultado => { console.log(resultado); // [2, 4, 6] });