O que são funções de ordem superior em Javascript?
Tags: javascript, node, programming
Published: 2021-09-19 22:17:37

Antes de dar uma definição formal, vamos entender onde elas podem ser úteis e por que usá-las.
Em um certo sistema, diversas operações de divisão de arrays são necessárias. 
Essa é uma das maneiras de implementar essas operações:
```js
const copyArrayAndDivideBy2 = (arr) => {
 const result = []
  for(let i = 0; i < arr.length; i++) {
   result.push(arr[i] / 2)
 }
  return result
}

const copyArrayAndDivideBy3 = (arr) => {
 const result = []
  for(let i = 0; i < arr.length; i++) {
   result.push(arr[i] / 3)
 }
  return result
}
```
Obviamente essa solução é péssima, praticamente todo o código é repetido, bugs conseguem se esconder facilmente e se caso a lógica mude, alguém vai precisar encontrar todas as funções e alterar uma por uma. Existem várias soluções melhores pra esse problema e uma delas é utilizar funções de ordem superior, que é o que vamos fazer a seguir.
## O que são funções de ordem superior?

Uma função de ordem superior, ou higher order function (HOF), como vamos chama-la, é uma função que recebe como argumento, ou retorna uma função. Isso é possível porque em Javascript, funções são [entidades de primeira classe](https://medium.com/@angelorubin/javascript-first-class-function-fun%C3%A7%C3%B5es-de-primeira-classe-7ebf63d2c83a), ou seja, é possível passar elas como argumentos para uma outra função.

Mas por que HOFs são importantes? Elas são ótimas ferramentas para evitar repetição desnecessária e seguir princípios como o [DRY e KISS](https://www.linkapi.solutions/blog/yagni-kiss-e-dry).

## Como usar em Javascript

Vamos continuar o exemplo anterior, refatorando aquelas funções para uma HOF.

Aqui, toda a parte de copiar o array e iterar sobre ele é separada da lógica, que vai ser passada como argumento quando essa função for chamada.

```jsx
const copyArrayAndManipulate = (arr, instructions) => {
// o parâmetro `instructions` normalmente é chamado de `callback`
// ele deve ser uma funcao que contém toda a lógica de manipulação
// do elemento, antes dele ser copiado para o resultado.
	const result = []
	for(let i = 0; i < arr.length; i++) {
		result.push(instructions(arr[i])
	}
	return result
}
```

Agora conseguimos utilizar essa função para fazer o mesmo que antes, mas evitando repetição de código.

```js
const divideBy2 = (input) => input / 2
const arrayDividedBy2 = copyArrayAndManipulate([2, 4, 6], divideBy2) // [1, 2, 3]
```

Simplificando ainda mais a implementação, podemos refatorar ela novamente:

```js
const arrayDividedBy2 = copyArrayAndManipulate(
	[2, 4, 6], 
	(input) => input / 2
) // [1, 2, 3]
```

Espero que agora tenha ficado muito mais claro onde usar essas funções

## HOFs na biblioteca padrão do Javascript

A função `copyArrayAndManipulate` é muito parecida com uma padrão da linguagem, a `Array.forEach` e isso não é coincidência, HOFs são utilizadas múltiplas vezes nas funções padrões do JS. 

Podemos implementar uma versão mais simples do `Array.forEach` com os conceitos que aprendemos nesse artigo, que funciona de uma forma muito similar a [original](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#polyfill).

```js
// recebe como parâmetro um array para iterar 
// e uma função com a lógica a ser executada
const iterateOver = (array, callback) => {
	let i = 0, len = array.length
	while(i < len) {
		const value = array[i]
		// executar a função passada por quem está chamando a função
		// e passar como argumento o elemento atual do array e o índice dele
		callback(value, i)
		i++	
	}
}
// chamando a função definida anteriormente e passando uma função
// de callback que imprime os elementos do array junto com o índice deles
iterateOver([1, 2, 3], (a, i) => {
	console.log(`elemento: ${a}, índice: ${i}`)
})
/* output
> elemento: 1, índice: 0
> elemento: 2, índice: 1
> elemento: 3, índice: 2
*/
```

## Conclusão

Funções de ordem superior são uma ferramenta extremamente útil para o dia a dia, elas são utilizadas em diversos lugares nas funções embutidas no JS e em outras bibliotecas, porém, o conceito pode ser um pouco difícil de se entender, se algo não ficou claro, por favor entre em contato [comigo](mailto:pedro.tashima@linkapi.com.br)!

### Referências

[https://eloquentjavascript.net/05_higher_order.html](https://eloquentjavascript.net/05_higher_order.html)

[https://frontendmasters.com/courses/javascript-hard-parts-v2/](https://frontendmasters.com/courses/javascript-hard-parts-v2/)

[https://www.developintelligence.com/blog/2016/10/javascript-functions-as-first-class-objects/#:~:text=Basically%2C first-class citizenship simply,be assigned key%3A value pairs](https://www.developintelligence.com/blog/2016/10/javascript-functions-as-first-class-objects/#:~:text=Basically%2C%20first%2Dclass%20citizenship%20simply,be%20assigned%20key%3A%20value%20pairs).

[https://medium.com/@angelorubin/javascript-first-class-function-funções-de-primeira-classe-7ebf63d2c83a](https://medium.com/@angelorubin/javascript-first-class-function-fun%C3%A7%C3%B5es-de-primeira-classe-7ebf63d2c83a)

[http://www.macoratti.net/16/04/net_dry1.htm#:~:text=O princípio DRY%2C 'Não se,e definitiva dentro do sistema."](http://www.macoratti.net/16/04/net_dry1.htm#:~:text=O%20princ%C3%ADpio%20DRY%2C%20'N%C3%A3o%20se,e%20definitiva%20dentro%20do%20sistema.%22)