Qual é a definição de uma função de ordem superior?
TL;DR
Uma função de ordem superior é qualquer função que recebe uma ou mais funções como argumentos, as quais ela usa para operar sobre alguns dados, e/ou retorna uma função como resultado.
Funções de ordem superior são destinadas a abstrair alguma operação que é executada repetidamente. O exemplo clássico disso é o Array.prototype.map(), que recebe um array e uma função como argumentos. O Array.prototype.map() então usa essa função para transformar cada item do array, retornando um novo array com os dados transformados. Outros exemplos populares em JavaScript são Array.prototype.forEach(), Array.prototype.filter() e Array.prototype.reduce(). Uma função de ordem superior não precisa apenas manipular arrays, pois existem muitos casos de uso para retornar uma função de outra função. Function.prototype.bind() é um exemplo que retorna outra função.
Vamos supor que temos um array de nomes no qual precisamos transformar cada string em maiúsculas.
const names = ['irish', 'daisy', 'anna'];
A maneira imperativa seria assim:
const transformNamesToUppercase = function (names) {const results = [];for (let i = 0; i < names.length; i++) {results.push(names[i].toUpperCase());}return results;};transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']
Use Array.prototype.map(transformerFn) torna o código mais curto e mais declarativo.
function transformNamesToUppercase(names) {return names.map((name) => name.toUpperCase());}transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']
Funções de ordem superior
Uma função de ordem superior é uma função que recebe outra função como argumento ou retorna uma função como resultado.
Funções como argumentos
Uma função de ordem superior pode receber outra função como argumento e executá-la.
function greet(name) {return `Hello, ${name}!`;}function greetName(greeter, name) {console.log(greeter(name));}greetName(greet, 'Alice'); // Hello, Alice!
Neste exemplo, a função greetName é uma função de ordem superior porque ela recebe outra função (greet) como argumento e a usa para gerar uma saudação para o nome fornecido.
Funções como valores de retorno
Uma função de ordem superior pode retornar outra função.
function multiplier(factor) {return function (num) {return num * factor;};}const double = multiplier(2);const triple = multiplier(3);console.log(double(5)); // 10console.log(triple(5)); // 15
Neste exemplo, a função multiplier retorna uma nova função que multiplica qualquer número pelo fator especificado. A função retornada é uma closure que lembra o valor de factor da função externa. A função multiplier é uma função de ordem superior porque retorna outra função.
Exemplos práticos
- Decorador de logging: Uma função de ordem superior que adiciona funcionalidade de logging a outra função:
function withLogging(fn) {return function (...args) {console.log(`Calling ${fn.name} with arguments`, args);return fn.apply(this, args);};}function add(a, b) {return a + b;}const loggedAdd = withLogging(add);console.log(loggedAdd(2, 3));// Saída// Chamando add com argumentos [2, 3]// 5
A função withLogging é uma função de ordem superior que recebe uma função fn como argumento e retorna uma nova função que registra a chamada da função antes de executar a função original.
- Memoization: Uma função de ordem superior que armazena em cache os resultados de uma função para evitar computações redundantes:
function memoize(fn) {const cache = new Map();return function (...args) {const key = JSON.stringify(args);if (cache.has(key)) {return cache.get(key);}const result = fn.apply(this, args);cache.set(key, result);return result;};}const memoizedFibonacci = memoize(function (n) {if (n <= 1) return n;return memoizedFibonacci(n - 1) + memoizedFibonacci(n - 2);});console.log(memoizedFibonacci(10)); // Saída: 55console.log(memoizedFibonacci(100)); // Saída: 354224848179262000000
A função memoize é uma função de ordem superior que recebe uma função fn como argumento e retorna uma nova função que armazena em cache os resultados da função original com base em seus argumentos.
- Lodash: Lodash é uma biblioteca utilitária que fornece uma ampla variedade de funções para trabalhar com arrays, objetos, strings e muito mais, sendo a maioria delas funções de ordem superior.
import _ from 'lodash';const numbers = [1, 2, 3, 4, 5];// Filtrar o arrayconst evenNumbers = _.filter(numbers, (n) => n % 2 === 0); // [2, 4]// Mapear o arrayconst doubledNumbers = _.map(numbers, (n) => n * 2); // [2, 4, 6, 8, 10]// Encontrar o valor máximo do arrayconst maxValue = _.max(numbers); // 5// Somar todos os valores do arrayconst sum = _.sum(numbers); // 15