voltar aos artigosfunctional programming
$cd~/artigos/higher-order-functions-javascript-ordem-superior
Functional Programming
série 33 Conceitos JS·parte 25 de 38

Higher-Order Functions: Quando Funções Viram Superpoderes

18 minVanderlei José Alamino

"Não é sobre o que você faz, é sobre como você abstrai o que faz." — adaptado de Eloquent JavaScript

Uma higher-order function (HOF) aceita funções como argumento ou retorna uma função. Em JavaScript isso é natural porque funções são de primeira classe — valores como números ou strings.

snippetJavaScript
function doTwice(action) {  action();  action();} const sayHello = createGreeter("Hello");function createGreeter(greeting) {  return name => `${greeting}, ${name}!`;}

Neste guia da série 33 Conceitos JS — projeto open source criado por Leonardo Maldonado — você vai aprender:

  • HOFs que recebem callbacks vs fábricas que retornam funções
  • Closures como base das fábricas
  • Métodos nativos map, filter, reduce
  • Erros comuns e quando não usar HOFs

Pré-requisitos: Closures e Callbacks — callbacks e HOFs são duas faces da mesma moeda.

higher-order-functions-javascript-ordem-superior.meta.jsonjson

// metadados do artigo

{
  "tag": "functional programming",
  "readTime": "18 min",
  "author": "Vanderlei José Alamino",
  "source": "33jsconcepts.com",
  "series": "33 Conceitos JS",
  "part": {
    "current": 25,
    "total": 38
  }
}
abrir fonte original
higher-order-functions-javascript-ordem-superior.mdmarkdown

Fonte de referência

Conteúdo adaptado a partir do guia original em inglês.

33jsconcepts.com
01

seção

Analogia: Cozinha de Restaurante

Receita de baixo nível: cada passo explícito. Receita de alto nível: "deixe de molho", "cozinhe em fogo baixo" — verbos que escondem detalhes.

HOFs são esses verbos abstratos: empacotam padrões (faça em cada item) e você passa o comportamento específico.

snippettext
ALTO:   radii.map(calculateArea)MÉDIO:  function map(arr, fn) { ... fn(item) ... }BAIXO:  for loop + fórmula manual
02

seção

O que é uma Higher-Order Function?

HOF faz pelo menos uma destas:

  1. Aceita função(ões) como argumento
  2. Retorna uma função
snippetJavaScript
function doTwice(action) { action(); action(); } doTwice(() => console.log("Hello!")); function createGreeter(greeting) {  return name => `${greeting}, ${name}!`;}const sayHello = createGreeter("Hello");sayHello("Alice");  // Hello, Alice!

Benefícios: menos repetição, abstração, utilitários reutilizáveis, composição.

03

seção

Funções de Primeira Classe

Em JS, funções são valores — você pode:

snippetJavaScript
const add = (a, b) => a + b; callTwice(fn => console.log("2x")); function createMultiplier(n) {  return x => x * n;}const double = createMultiplier(2);

Atribuir, passar como argumento, retornar de outra função — fundamento de toda programação funcional em JS.

04

seção

HOFs que Aceitam Funções

repeat — estrutura uma vez, comportamento variável:

snippetJavaScript
function repeat(times, action) {  for (let i = 0; i < times; i++) action(i);} repeat(3, i => console.log(`Iteração ${i}`));

calculate — loop genérico + fórmula:

snippetJavaScript
function calculate(radii, formula) {  return radii.map(formula);} const area = r => Math.PI * r * r;calculate([1, 2, 3], area);

unless — nova abstração de fluxo:

snippetJavaScript
function unless(cond, action) {  if (!cond) action();}
05

seção

HOFs que Retornam Funções

Fábrica greaterThan:

snippetJavaScript
function greaterThan(n) {  return m => m > n;} const gt10 = greaterThan(10);gt10(11);  // true

Wrapper noisy — padrão decorator:

snippetJavaScript
function noisy(fn) {  return (...args) => {    console.log("args:", args);    const result = fn(...args);    console.log("result:", result);    return result;  };} noisy(Math.max)(3, 1, 4);  // log + 4

Validadores e formatadores:

snippetJavaScript
const isValidAge = createValidator(0, 120);const formatDollars = createFormatter("$", "");

Aplicação parcial:

snippetJavaScript
function partial(fn, ...preset) {  return (...later) => fn(...preset, ...later);}const sayHello = partial(greet, "Hello", "!");
06

seção

Closures e Variáveis Privadas

Fábricas dependem de closures — função interna lembra variáveis externas:

snippetJavaScript
function createCounter(start = 0) {  let count = start;  return () => ++count;} const c1 = createCounter();const c2 = createCounter(100);c1();  // 1c2();  // 101
snippetJavaScript
function createBankAccount(balance) {  return {    deposit(n) { balance += n; return balance; },    getBalance() { return balance; },  };}// balance é privado — inacessível de fora

Veja Closures para aprofundar.

07

seção

HOFs Nativas de Array

MétodoFunçãoRetorna
forEach(fn)executa em cadaundefined
map(fn)transformanovo array
filter(fn)filtranovo array
reduce(fn, init)acumulavalor único
find(fn)primeiro matchelemento
some / everytesteboolean
snippetJavaScript
[1, 2, 3, 4, 5]  .filter(n => n > 2)  .map(n => n * 2)  .reduce((s, n) => s + n, 0);  // 24

Todas aceitam função como argumento — são HOFs nativas.

08

seção

Erros Comuns

Arrow sem return explícito

snippetJavaScript
// ❌nums.map(n => { n * 2; })// ✅nums.map(n => n * 2)nums.map(n => { return n * 2; })

Perder this em callbacks

Use .bind(this), arrow wrapper ou arrow no método — veja this, call, apply & bind.

Gotcha parseInt com map

snippetJavaScript
["1","2","3"].map(parseInt);  // [1, NaN, NaN]// map passa (elem, index) — index vira radix!["1","2","3"].map(s => parseInt(s, 10));

HOF quando loop simples é mais claro

Não force reduce se um for...of somando é mais legível.

09

seção

Perguntas Clássicas de Entrevista

10

seção

Teste Seu Conhecimento

$ summary --quick

Resumo rápido

  • HOF — aceita função como arg ou retorna função
  • Funções de primeira classe — atribuir, passar, retornar
  • HOF + callback — estrutura fixa, comportamento variável
  • Fábricas — funções especializadas a partir de template
  • Closures — variáveis privadas e estado lembrado
  • map, filter, reduce, forEach — HOFs nativas de array
  • Abstração — trabalhe no nível certo do problema
  • Gotchas: this, return em arrow, parseInt + map
  • Legibilidade primeiro — loop simples às vezes vence

Créditos da série

Este artigo faz parte de uma série de estudos inspirada no projeto 33 Conceitos JS, criado por Leonardo Maldonado. Todo o conteúdo original está disponível em 33jsconcepts.com.