Este tutorial apresentará funções de ordem superior, como usá-las e seus benefícios.
Como passar uma função como argumento para outra função.
Passar funções como argumentos para outras funções é uma das maneiras de personalizar o comportamento das funções. Ele permite passar diferentes funções como parâmetros para uma única função, tornando seu código mais limpo e reutilizável. Vejamos como podemos fazer isso.
Exemplo 1
Considere o calculate()
função, que nos ajuda a realizar diversos cálculos matemáticos. São necessários dois números, aeb, e uma função de operação como argumentos. Definimos então as diferentes funções matemáticas, ou seja, add
e subtract.
Usamos então o calculate()
funcionar com qualquer uma das funções matemáticas e fornecer os números inteiros nos quais as operações matemáticas serão realizadas.
1 |
function calculate(a, b, operation) { |
2 |
return operation(a,b); |
3 |
}
|
4 |
|
5 |
|
6 |
function add(a, b) { |
7 |
return a + b; |
8 |
}
|
9 |
|
10 |
function subtract(a, b) { |
11 |
return a - b; |
12 |
}
|
13 |
|
14 |
|
15 |
console.log(calculate(10, 5, add)); //output // 15 |
16 |
console.log(calculate(10, 5, subtract)); //output //5 |
Como você pode ver acima, ao separar as diferentes operações, nosso código pode ser facilmente extensível sem alterar o calculate ()
função.
Exemplo 2
Vejamos outro exemplo. Suponha que você tenha o conjunto de nomes mostrado abaixo;
1 |
const names = ['Ann','Alex', 'Barman', 'zen','liz', 'Christopher', 'Isabella'] |
Então, suponha que você tenha a tarefa de filtrar as pessoas cujos nomes têm três caracteres ou menos; você provavelmente pensaria em algo assim:
1 |
function shortNames(namesArr){ |
2 |
const result = [] |
3 |
for(i=0; i< namesArr.length; i++){ |
4 |
if (namesArr[i].length <= 3){ |
5 |
result.push(namesArr[i]) |
6 |
|
7 |
}
|
8 |
}
|
9 |
return result |
10 |
}
|
11 |
|
12 |
console.log(shortNames(names)) //output //[ 'Ann', 'zen', 'Liz' ] |
Aqui, criamos uma função shortNames
, que usa uma matriz de nomes como parâmetro. Então, definimos um array vazio chamado result
. Então, criamos um for
loop, que percorre cada elemento da matriz e verifica seu comprimento. Se o comprimento de um elemento for menor ou igual a 3 caracteres, o elemento será considerado um nome abreviado e enviado para a matriz de resultados. Finalmente, retornamos o novo array contendo os nomes curtos filtrados.
Suponha que também precisamos obter todas as pessoas com nomes longos, ou seja, nomes com oito ou mais caracteres; nossa função seria semelhante à shortNames()
função
1 |
function LongNames(namesArr){ |
2 |
const result = [] |
3 |
for(i=0; i< namesArr.length; i++){ |
4 |
if (namesArr[i].length >= 8){ |
5 |
result.push(namesArr[i]) |
6 |
|
7 |
}
|
8 |
}
|
9 |
return result |
10 |
}
|
11 |
console.log(LongNames(names)); //ouput // [ 'Christopher', 'Isabella' ] |
O LongNames
e shortNames
ambas as funções executam tarefas semelhantes, como:
- percorrendo a matriz de nomes
- filtrando cada nome na matriz com base na condição especificada
- empurrando elementos que satisfazem a condição para um novo array
No entanto, podemos encurtar nosso código e evitar tarefas repetitivas criando uma função comum. Como não precisamos de toda a lógica em nossas duas funções acima, podemos reescrevê-las conforme mostrado abaixo.
1 |
function isShortName(name, length) { |
2 |
return name.length <= length; |
3 |
}
|
4 |
|
5 |
function isLongName(name, length) { |
6 |
return name.length >= length; |
7 |
}
|
Aqui definimos nossas funções isShortName
e isLongName
que aceita dois argumentos: nome e comprimento. isShortName
irá verificar se o nome fornecido é menor ou igual ao comprimento especificado. Ele retorna true
se o nome fornecido satisfizer a condição.
IsLongName()
faz algo semelhante, mas retorna true
se o nome fornecido for maior ou igual ao comprimento fornecido.
A seguir, criaremos um filterNames
função para filtrar nomes com base em diferentes condições. O filterNames
função receberá três argumentos:
- matriz de nomes.
- A função de retorno de chamada (pode ser
IsLongName
ouisShortName
). - A condição de comprimento usada para filtrar os nomes.
1 |
function filterNames(namesArr, conditionFn, length) { |
2 |
const result = []; |
3 |
for (let i = 0; i < namesArr.length; i++) { |
4 |
if (conditionFn(namesArr[i], length)) { |
5 |
result.push(namesArr[i]); |
6 |
}
|
7 |
}
|
8 |
return result; |
9 |
}
|
Então agora, se decidirmos usar o filterNames()
com qualquer uma das funções de retorno de chamada, obteremos a mesma saída.
1 |
console.log(filterNames(names, isShortName, 3)); // [ 'Ann', 'zen', 'Liz' ] |
2 |
console.log(filterNames(names, isLongName, 8)); //[ 'Christopher', 'Isabella' ] |
Exemplos de funções de ordem superior
Funções de ordem superior são comumente usadas para mapear, filtrar e reduzir matrizes. As funções de ordem superior mais comumente usadas incluem:
- filtro()
- mapa()
- reduzir()
Usando o método filter()
Como o nome sugere, o filter()
O método filtra elementos em uma matriz com base na condição especificada. Quando aplicado a uma matriz, o filter()
O método criará outro array com apenas os elementos do array original que satisfazem a condição na função.
Considere a matriz abaixo, que consiste nos nomes e salários de alguns funcionários.
1 |
const funcionários = [ |
2 |
{name: "Alice",salary: 25000 }, |
3 |
{name: "Bob",salary: 30000}, |
4 |
{name: "Charlie",salary: 28000}, |
5 |
{name: "Cate",salary: 100000,}, |
6 |
{name: "Mike",salary: 120000,}, |
7 |
{name: "Lucy",salary: 55000,}, |
8 |
{name: "Liam",salary: 70000,}, |
9 |
]
|
Suponha que queiramos filtrar os funcionários que ganham mais de 70.000. Uma maneira de fazer isso seria usar um for
fazer um loop, fazer um loop sobre cada elemento e, a cada iteração, enviar o funcionário que satisfaz nossa condição para um novo array, conforme mostrado abaixo.
1 |
const filteredEmployees = [] |
2 |
for(i =0 ;i |
3 |
if(employees[i].salary >=70000 ){ |
4 |
filteredEmployees.push(employees[i]) |
5 |
}} |
6 |
|
7 |
console.log(filteredEmployees); |
Mesmo que a função funcione conforme o esperado, existem maneiras melhores de implementar a solução. O filter ()
método é uma excelente solução para o nosso problema. Sua sintaxe é assim;
1 |
const newArray = array.filter(callbackFn,thisArg) |
Onde callbackFn
é a função para filtrar elementos. O callbackFn
leva três argumentos opcionais: element
, index
e array
. thisArg
é opcional.
Vamos primeiro definir o callbackFn, que receberá um objeto funcionário e verificará se o valor na propriedade salário é superior a 70.000.
1 |
function checkSalary(employee){ |
2 |
return employee.salary >= 70000 |
3 |
}
|
A seguir, vamos aplicar o filter()
método para o nosso callbackFxn
e atribuí-lo ao filtredArray
.
1 |
const filteredArray = employees.filter(checkSalary); |
2 |
console.log(filteredArray) |
Nossa saída ficará assim:
1 |
[
|
2 |
{ name: 'Cate', salary: 100000 }, |
3 |
{ name: 'Mike', salary: 120000 }, |
4 |
{ name: 'Liam', salary: 70000 } |
5 |
]
|
Usando o método Map()
O map()
método é outra função de ordem superior que cria um novo array aplicando uma função de retorno de chamada a cada elemento do array original.
A sintaxe é semelhante a esta:
1 |
const newArray = originalArray.map(callbackFn, thisArg); |
onde o callbackFn
recebe os seguintes parâmetros,
currentValue
- o elemento atual sendo processadoindex
- o índice do elemento atual que está sendo processadoarray
-a matriz original
thisArg
é opcional.
Dada a matriz de alunos abaixo, que contém os nomes e as notas dos alunos para diferentes disciplinas e notas gerais, queremos extrair apenas os nomes e as notas gerais da matriz.
1 |
const estudantes = [ |
2 |
{
|
3 |
names: "Alice Bob",Math: 85,Science: 92,History: 78,English: 88,Art: 95, |
4 |
grade:87.6 |
5 |
},
|
6 |
{
|
7 |
names: "Michael Smith",Math: 76,Science: 89,History: 92,English: 80, |
8 |
Art: 91, |
9 |
grade:85.6 |
10 |
},
|
11 |
{
|
12 |
names: "William Brown",Math: 70,Science: 78,History: 75,English: 88,Art: 79, |
13 |
grade:76 |
14 |
},
|
15 |
{
|
16 |
names: "Julia Lee", Math: 52, Science: 63, History: 76, English: 87, |
17 |
Art: 94, |
18 |
grade:74.2 |
19 |
},
|
20 |
{
|
21 |
names:"George Harrison",Math: 88,Science: 77,History: 50,English: 84, |
22 |
Art: 71, |
23 |
grade:74 |
24 |
},
|
25 |
];
|
Podemos usar o map()
método para recuperar os nomes dos alunos e notas gerais. Primeiro, vamos criar a função de retorno de chamada, que recebe um aluno como argumento e extrai o nome do aluno e a nota geral.
1 |
function gradeOnly(student){ |
2 |
return ({names:student.names, grade: student.grade}) |
3 |
}
|
Nossa função de retorno de chamada pegará um objeto aluno como argumento e retornará um novo objeto contendo apenas os nomes e as propriedades das notas.
A seguir, usaremos o método map() para criar um novo array aplicando o método gradeOnly()
para cada aluno na matriz de alunos. O map()
método irá iterar através de cada elemento da matriz do aluno e aplicar o gradeOnly()
função.
1 |
const studentsData = students.map(gradeOnly) |
2 |
console.log(studentsData) |
Nossa saída será:
1 |
[
|
2 |
{ names: 'Alice Bob', grade: 87.6 }, |
3 |
{ names: 'Michael Smith', grade: 85.6 }, |
4 |
{ names: 'William Brown', grade: 76 }, |
5 |
{ names: 'Julia Lee', grade: 74.2 }, |
6 |
{ names: 'George Harrison', grade: 74 } |
7 |
]
|
Usando funções de seta, podemos simplificar esta expressão da seguinte forma:
1 |
const studentsData = students.map( |
2 |
student=> ({names:student.names, grade: student.grade})) |
3 |
console.log(studentsData) |
Usando o método Array.reduce()
Como o nome sugere, o reduce()
O método pega um array e o reduz a um único valor. A sintaxe do método de redução é semelhante a esta.
1 |
array.reduce(function(total, currentValue, currentIndex, arr), initialValue) |
onde
- O total será o resultado
- o currentValue será o elemento atual durante o processo de iteração
- O valor inicial será 0
- currentIndex e arr são opcionais
Suponha que você queira descobrir a soma dos números na matriz de números abaixo usando o reduce()
método:
1 |
numbers = [10,20,30,40] |
Vamos começar definindo a função de retorno de chamada que receberá o total e o número como argumentos. A função de retorno de chamada retornará o resultado da adição de cada número em nosso array original ao total.
1 |
function addNumbers(total,number){ |
2 |
return total+=number |
3 |
}
|
A seguir, aplique o reduce()
método para a matriz de números e use o addNumbers
como a função de retorno de chamada. Cada elemento na matriz de números é aplicado à função de retorno de chamada para cada iteração.
1 |
const cumulativeTotal =numbers.reduce(addNumbers); |
2 |
console.log(cumulativeTotal); //output //100 |
A saída será 100, conforme esperado. Se não definirmos um valor inicial, o primeiro elemento será considerado o valor inicial e a saída ainda será a mesma.
1 |
numbers = [10,20,30,40] |
2 |
numbers.reduce(function(total, number){ |
3 |
return total+number |
4 |
})
|
Podemos encurtar ainda mais nossa expressão usando funções de seta da seguinte forma:
1 |
const cumulativeTotal = numbers.reduce((total,number) => total+=number) |
2 |
console.log(cumulativeTotal); //output //100 |
Benefícios das funções de ordem superior
- Funções de ordem superior abstraem a lógica subjacente necessária para a execução de tarefas. Por exemplo, quando usamos o
reduce()
método, abstraímos a lógica subjacente de iterar cada elemento, somando-o ao total e retornando o resultado. Não precisamos escrever explicitamente a lógica de iteração e acumulação; a função de redução cuidou disso para nós. - A utilização de funções de ordem superior melhora a legibilidade e a manutenção do código em comparação com a implementação da mesma funcionalidade com loops.
- Funções de ordem superior também tornam seu código reutilizável.
Aprimore seu jogo JS com Tuts+
Conclusão
Este tutorial apresentou funções de ordem superior e ofereceu exemplos práticos e cenários onde elas podem ser aplicadas à programação JavaScript. Incorporar funções de ordem superior em suas práticas de desenvolvimento pode aprimorar significativamente suas habilidades como desenvolvedor JavaScript.