Se você está aprendendo JavaScript, deve ter se deparado com o conceito de "Função de Ordem Superior". Isso pode parecer algo muito complicado, mas, de fato, não é.
JavaScript é adequado para programação funcional porque suporta o conceito de funções de ordem superior. Tais funções são amplamente usadas na linguagem e, se você programou em JS, provavelmente já trabalhou com elas sem nem mesmo saber.

Para entender completamente esse conceito, primeiro você precisa entender o conceito de programação funcional (Programação Funcional) e quais funções são de primeira classe (Funções de Primeira Classe).
O material, cuja tradução publicamos, é destinado a iniciantes, visa explicar o conceito de funções de ordem superior e demonstrar como usá-las em JavaScript.
O que é programação funcional?
Se você descrever o conceito de programação funcional em palavras simples, verifica-se que essa é uma abordagem da programação, usando a qual você pode passar funções para outras funções como parâmetros e usar funções como valores retornados por outras funções. Participando da programação funcional, projetamos a arquitetura do aplicativo e escrevemos código usando funções.
Entre as linguagens que suportam programação funcional estão JavaScript, Haskell, Clojure, Scala e Erlang.
Funções de primeira classe
Se você estiver aprendendo JavaScript, poderá ouvir que em um idioma as funções são tratadas como objetos de primeira classe. Isso ocorre porque no JavaScript, como em outros idiomas que suportam programação funcional, as funções são objetos.
Em particular, em JS, as funções são representadas como objetos de um tipo especial - esses são objetos do tipo
Function
. Considere um exemplo:
function greeting() { console.log('Hello World'); } // greeting(); // 'Hello World'
Para provar que funções em JavaScript são objetos, podemos fazer o seguinte, continuando o exemplo anterior:
// , greeting.lang = 'English'; // 'English' console.log(greeting.lang);
Observe que, ao adicionar suas próprias propriedades a objetos padrão no JavaScript não causa mensagens de erro, isso não é recomendado. Você não deve adicionar suas próprias propriedades às funções. Se você precisar armazenar algo em um objeto, é melhor criar um objeto especial para isso.
No JavaScript com funções, você pode fazer o mesmo com entidades de outros tipos, como
Object
,
String
,
Number
. As funções podem ser passadas como parâmetros para outras funções. Tais funções, transferidas para outras pessoas, geralmente agem como funções de retorno de chamada (retornos de chamada). As funções podem ser atribuídas a variáveis, armazenadas em matrizes e assim por diante. É por isso que funções em JS são objetos de primeira classe.
Atribuindo funções a variáveis e constantes
As funções podem ser atribuídas a variáveis e constantes:
const square = function(x) { return x * x; }
As funções atribuídas a variáveis ou constantes podem ser atribuídas a outras variáveis ou constantes:
const foo = square;
Passando funções como parâmetros
As funções podem ser passadas como parâmetros para outras funções:
function formalGreeting() { console.log("How are you?"); } function casualGreeting() { console.log("What's up?"); } function greet(type, greetFormal, greetCasual) { if(type === 'formal') { greetFormal(); } else if(type === 'casual') { greetCasual(); } } // 'What's up?' greet('casual', formalGreeting, casualGreeting);
Agora que sabemos como as funções de primeira classe se comportam, vamos falar sobre funções de ordem superior.
Funções de ordem superior
Funções de ordem superior são funções que funcionam com outras funções, tomando-as como parâmetros ou retornando-as. Simplificando, uma função de ordem superior é uma função que aceita uma função como argumento ou retorna uma função como um valor de saída.
Por exemplo, as funções JavaScript
Array.prototype.map
,
Array.prototype.filter
e
Array.prototype.reduce
são funções de ordem superior.
Funções de ordem superior em ação
Considere exemplos de uso de funções de ordem superior incorporadas ao JS e compare essa abordagem com ações semelhantes sem usar essas funções.
▍ Método Array.prototype.map
O método
map()
cria uma nova matriz, chamando, para processar cada elemento da matriz de entrada, o retorno de chamada passado como argumento. Este método pega todo valor retornado pelo retorno de chamada e o coloca na matriz de saída.
A função de retorno de chamada passada para
map()
leva três argumentos:
element
(elemento),
index
(índice) e
array
(matriz). Vejamos alguns exemplos.
Exemplo No. 1
Suponha que temos uma matriz de números e queremos criar uma nova matriz que contenha os resultados da multiplicação desses números por 2. Considere maneiras de resolver esse problema usando funções de ordem superior e sem elas.
Resolvendo um problema sem usar funções de ordem superior
const arr1 = [1, 2, 3]; const arr2 = []; for(let i = 0; i < arr1.length; i++) { arr2.push(arr1[i] * 2); } // [ 2, 4, 6 ] console.log(arr2);
Resolvendo um problema usando um mapa de funções de ordem superior
const arr1 = [1, 2, 3]; const arr2 = arr1.map(function(item) { return item * 2; }); console.log(arr2);
Você pode até reduzir o volume desse código se usar a função de seta:
const arr1 = [1, 2, 3]; const arr2 = arr1.map(item => item * 2); console.log(arr2);
Exemplo No. 2
Suponha que temos uma matriz contendo o ano de nascimento de algumas pessoas e precisamos criar uma matriz que atinja a idade em 2018. Considere, como antes, a solução para esse problema de duas maneiras.
Resolvendo um problema sem usar funções de ordem superior
const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = []; for(let i = 0; i < birthYear.length; i++) { let age = 2018 - birthYear[i]; ages.push(age); }
Resolvendo um problema usando um mapa de funções de ordem superior
const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = birthYear.map(year => 2018 - year);
▍ Método Array.prototype.filter
O método
filter()
cria, com base na matriz, uma nova matriz na qual caem os elementos da matriz original, correspondendo à condição especificada na função de retorno de chamada passada para esse método. Esta função leva, como no caso do método
map()
, 3 argumentos:
element
,
index
e
array
.
Considere um exemplo construído da mesma maneira que ao considerar o método
map()
.
Exemplo
Suponha que tenhamos uma matriz contendo objetos cujas propriedades armazenem informações sobre o nome e a idade dos representantes de um determinado grupo de pessoas. Precisamos criar uma matriz na qual haverá informações apenas sobre os representantes adultos deste grupo (aqueles cuja idade atingiu 18 anos).
Resolvendo um problema sem usar funções de ordem superior
const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = []; for(let i = 0; i < persons.length; i++) { if(persons[i].age >= 18) { fullAge.push(persons[i]); } } console.log(fullAge);
Resolvendo um problema usando um filtro de função de ordem superior
const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = persons.filter(person => person.age >= 18); console.log(fullAge);
▍ Método Array.prototype.reduce
O método
reduce()
processa cada elemento da matriz usando um retorno de chamada e coloca o resultado em um único valor de saída. Este método usa dois parâmetros: retorno de chamada e valor inicial opcional (
initialValue
).
Um retorno de chamada aceita quatro parâmetros:
accumulator
(acumulador),
currentValue
(valor atual),
currentIndex
(índice atual),
sourceArray
(matriz de origem).
Se o parâmetro
initialValue
for fornecido ao
initialValue
, no início do método, o
accumulator
será igual a esse valor e o primeiro elemento da matriz processada será gravado em
currentValue
.
Se o parâmetro
initialValue
não for fornecido ao método, o primeiro elemento da matriz será gravado no
accumulator
e o segundo no
currentValue
.
Exemplo
Suponha que tenhamos uma matriz de números. Precisamos calcular a soma de seus elementos.
Resolvendo um problema sem usar funções de ordem superior
const arr = [5, 7, 1, 8, 4]; let sum = 0; for(let i = 0; i < arr.length; i++) { sum = sum + arr[i]; }
Resolver um problema usando uma função de ordem superior reduz
Primeiro, considere usar o método
reduce()
sem fornecer um valor inicial.
const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; });
Cada vez que um retorno de chamada é chamado com um
currentValue
passado para
currentValue
, ou seja, o próximo elemento da matriz, seu parâmetro
accumulator
acaba contendo os resultados da operação anterior, ou seja, o que foi retornado da função na iteração anterior. Após a conclusão deste método, o resultado final cai na
sum
constante.
Agora, vamos ver como será a solução para o problema se passarmos o valor inicial para o método
reduce()
.
const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }, 10);
Como você pode ver, o uso de uma função de ordem superior tornou nosso código mais limpo, mais conciso e fácil de ler.
Crie funções personalizadas de ordem superior
Até o momento, trabalhamos com funções de ordem superior incorporadas ao JS. Agora vamos criar nossa própria função que funciona com outras funções.
Imagine que o JavaScript não possui um método padrão de matriz
map()
. Nós mesmos podemos criar esse método, que será expresso no desenvolvimento de uma função de ordem superior.
Suponha que tenhamos uma matriz de seqüências de caracteres e gostaríamos de criar em sua base uma matriz com números, cada um dos quais representa o comprimento da sequência armazenada em algum elemento da matriz original.
const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C']; function mapForEach(arr, fn) { const newArray = []; for(let i = 0; i < arr.length; i++) { newArray.push( fn(arr[i]) ); } return newArray; } const lenArray = mapForEach(strArray, function(item) { return item.length; });
Neste exemplo, criamos uma função de ordem superior
mapForEach
, que
mapForEach
uma matriz e uma função de retorno de chamada
fn
. A função
mapForEach
matriz em um loop e chama o retorno de chamada
fn
a cada iteração desse loop.
O retorno de chamada
fn
aceita o elemento de string atual da matriz e retorna o comprimento desse elemento. O que a função
fn
retorna é usado no comando
newArray.push()
e entra na matriz que
mapForEach()
retornará. Essa matriz será gravada na constante
lenArray
.
Sumário
Neste artigo, falamos sobre funções de ordem superior e exploramos algumas das funções internas do JavaScript. Além disso, descobrimos como criar suas próprias funções de ordem superior.
Em poucas palavras, pode-se dizer que a essência das funções de ordem superior são funções que podem assumir outras funções como argumentos e retornar outras funções como resultados de seu trabalho. Trabalhar com outras funções em funções de ordem superior parece o mesmo que trabalhar com outros objetos.
Caros leitores! Você precisa escrever suas próprias funções de ordem superior?
