Como usar uma IIFE (função autoinvocada) para criar um código modular e sem conflitos de escopo
Tags: iife, javascript, funcaoautoinvocada, encapsulamento
Published: 2023-08-03 23:20:10

## Desvende o super poder das IIFEs, ou funções autoinvocadas, para criar um código modular e sem conflitos de escopo.
 
IIFE não tem nada a ver com o `if` de `if else` (queria tirar esse elefante branco da sala 🤣).
 
A IIFE, ou Immediately Invoked Function Expression, é a declaração e execução de uma função juntas.
 
Declaração? Execução? Relembre!
 
Uma função em Javascript tem 2 "momentos":
 
1. Declaração
2. Execução/invocação
 
```javascript
// Declaração

function displayName(name) {
  console.log(name);
}

// Execução

displayName('Menezes');
```
 
Legal, mas... para quê?
 
## O que é e para que serve uma IIFE? A função invocada imediatamente
 
**Uma IIFE é a declaração e execução de uma função Javascript em apenas uma expressão.**
 
Estruturalmente, escrever uma IIFE é bastante simples. Primeiro, escreva uma função normal:
 
```javascript
function() {
  console.log('Menezes');
}
```
 
Agora coloque toda essa declaração dentro de um parênteses:
 
```javascript
(function() {
  console.log('Menezes');
})
```
 
E para fechar, adicione outro parênteses no final:
 
```javascript
(function() {
  console.log('Menezes');
})();
```
 
O primeiro parênteses recebe a declaração da função. E o  , os argumentos da execução, ou fica vazio.
 
Vou modificar ela um pouco, e informar o nome que quero mostrar no parâmetro:
 
```javascript
(function(name) {
  console.log(name);
})('Menezes');
```
 
Veja o que aconteceu na ordem de execução:
 
- **Linha 3**: informo a string `'Menezes'` como argumento para a IIFE dentro do parênteses de execução
- **Linha 1**: a declaração da IIFE recebe esse argumento como `name` no parâmetro
- **Linha 2**: o corpo da função usa o parâmetro `name` para escrever seu valor no console
 
E isso tudo aconteceu "de uma vez".
 
Quase sempre, a função que as pessoas declaram em uma IIFE é anônima, ou seja, não tem nome. Por isso você também pode chamá-la de [Self-Executing Anonymous Function](https://developer.mozilla.org/pt-BR/docs/Glossary/Self-Executing_Anonymous_Function).
 
É claro que você pode nomeá-la, mas vai servir apenas como organização. Isso porque, logo após executar a IIFE, você não pode executá-la pelo nome:
 
```javascript
(function showName(name) {
  console.log(name);
})('Menezes'); // Resultado: 'Menezes'

showName('André'); // Resultado: ReferenceError: showName is not defined
```
 
Caso você queira chamar a função novamente no futuro, não crie uma IIFE:
 
```javascript
function showName(name) {
  console.log(name);
}

showName('Menezes'); // Resultado: 'Menezes'

showName('André'); // Resultado: 'André'
```
 
Uma última característica importante, é sobre atribuir uma IIFE a uma variável. Ela irá receber o retorno da função, e não a declaração dela.
 
Veja esse exemplo:
 
```javascript
const result = function(number) {
  return number + 5;
}
```
 
Dessa forma, `result` é uma função que recebe o parâmetro `number` e retorna ele mais 5.
 
Porém assim o cenário é outro:
 
```javascript
const result = (function(number) {
  return number + 5;
})(3);
```
 
Agora, `result` é o próprio retorno da função, ou seja, o resultado da soma. Nesse caso, 8.
 
Quando vi uma IIFE pela primeira vez, fiquei com uma dúvida. Por que não executar as linhas diretamente sem envolver numa função anônima?
 
## Vantagens de criar uma IIFE
 
Em resumo, são duas:
 
1. Evitar conflito de variáveis com o encapsulamento
2. Imutabilidade
 
### Evitar conflito de variáveis com o encapsulamento
 
O velho problema de nomear as coisas.
 
Veja esse exemplo:
 
```javascript
function soma(numA, numB) {
  return numA + numB;
}

var result = 0;
console.log(result); // 0

// algumas linhas depois...

var result = soma(4, 8);
console.log(result); // 12

// muitas linhas depois...

var result = soma(12, 3);
console.log(result); // 15

// a lot of linhas depois...

console.log(result); // ???
```
 
Aqui eu mostrei que a variável `result` recebe diferentes valores ao longo do arquivo. E isso dificulta saber qual é o seu valor na última linha. Claro, em um arquivo pequeno fica fácil, mas em outro cenário isso seria bem trabalhoso.
 
E se sua página importa mais de um arquivo Javascript, esse conflito de nome de variáveis também acontece entre eles.
 
Se criasse com `const`, isso já geraria um erro.
 
---
 
Por outro lado, com IIFEs isso não acontece:
 
```javascript
function soma(numA, numB) {
  return numA + numB;
}

var result = 0;
console.log(result); // 0

// algumas linhas depois...

(function() {
  var result = soma(4, 8);
  console.log(result); // 12
})();

// muitas linhas depois...

(function() {
  var result = soma(12, 3);
  console.log(result); // 15
})();

// a lot of linhas depois...

console.log(result); // 0
```
 
**Com as IIFEs, o valor que declarei para a variável `result` não altera a primeira ocorrência dessa variável.** E assim fica fácil saber que, na última linha, ela mantém o mesmo valor de sua declaração inicial.
 
Mas e se eu precisasse usar o valor de `result` dentro de uma a IIFE?
 
### Imutabilidade
 
A imutabilidade é um assunto muito importante dentro do paradigma de programação funcional.
 
Veja o exemplo abaixo:
 
```javascript
var code = 10;

(function(code) {
  code = code + 5;
  console.log(code); // 15
})(code);

console.log(code) // 10
```
 
**Mesmo que você altere o valor da variável `code` dentro da IIFE, no final do código ela mantém o valor inicial, `10`**.
 
No seu dia a dia, você pode encontrar outras vantagens de usar uma IIFE. E já que falei da sua rotina de trabalho, veja agora casos de uso de uma função autoinvocada.
 
## Exemplos de uso de IIFE
 
### Proteger variáveis do escopo global
 
Isso fica na conta do encapsulamento.
 
Se você viu a maioria dos exemplos que mostrei até aqui, então já entendeu.
 
Uma IIFE cria um escopo de função que evita conflitos. **Assim, as variáveis que você criou em uma IIFE, não conflita com as de outros escopos**. Isso envolve conflitar tanto com as suas variáveis, quanto com as de bibliotecas externas. Apesar de que esses pacotes já envolvem suas funções e variáveis em blocos de funções.
 
E já que elas não estão em conflito, fica mais confortável criar variáveis e função para cada parte do código.
 
Posteriormente, você pode inicializar esses blocos um por vez.
 
### Inicializar blocos de código
 
Imagine uma página com dois modais um pouco diferentes.
 
Um deles (`modalA`) possui um backdrop que ao clicar fecha o modal. Já o outro, `modalB`, não, é um modal bloqueante.
 
Apesar dessa diferença, ambos são modais, e compartilham alguns comportamentos:
 
```javascript
// Funções compartilhadas

function openModal() { /* ... */ }
function closeModal() { /* ... */ }

// modalA: não bloqueante

const modal = document.querySelector('.modalA .modal');
const backdrop = document.querySelector('.modalA .backdrop');
  
backdrop.addEventListener('click', closeModal);

// modalB: bloqueante

const modal = document.querySelector('.modalB .modal');
const backdrop = document.querySelector('.modalB .backdrop');
  
// não adiciona evento de clique no backdrop
```
 
Se você iniciar os modais assim, haverá um conflito das variáveis `modal` e `backdrop`.
 
Para resolver isso, **envolva cada modal em uma IIFE que inicializa seus comportamentos**:
 
```javascript
// Funções compartilhadas

function openModal() { /* ... */ }
function closeModal() { /* ... */ }

// modalA: não bloqueante

(function modalA() {
  const modal = document.querySelector('.modalA .modal');
  const backdrop = document.querySelector('.modalA .backdrop');
  
  backdrop.addEventListener('click', closeModal);
})();

// modalB: bloqueante

(function modalB() {
  const modal = document.querySelector('.modalB .modal');
  const backdrop = document.querySelector('.modalB .backdrop');
  
  // não adiciona evento de clique no backdrop
})();
```
 
No exemplo acima, criei funções não anônimas nas IIFEs apenas para organização.
 
Além de **inicializar** componentes, você pode preparar módulos e usá-los no futuro.
 
### Modularidade
 
Esse foi o exemplo mais interessante de criar.
 
**Com uma immediately invoked function expression você pode criar módulos**. Esses módulos criam valores privados que não podem ser alterados de fora. Apenas os métodos que você escolhe expor, por meio do `return`, podem alterar os valores privados.
 
Veja o código abaixo, e em seguida eu explico o que está acontece:
 
```javascript
const contaCorrente = (function() {
  let saldo = 0;

  function depositar(value) {
    saldo = saldo + value;
  }

  function sacar(value) {
    saldo = saldo - value;
  }

  function verSaldo() {
    return saldo;
  }

  return { depositar, sacar, verSaldo };
})();

contaCorrente.depositar(30);
contaCorrente.depositar(40);
contaCorrente.sacar(50);
contaCorrente.sacar(60);

console.log(contaCorrente.verSaldo()); // -40

contaCorrente.depositar(100);

console.log(contaCorrente.verSaldo()); // +60
```
 
Eu criei uma `contaCorrente` que recebe o retorno de uma IIFE. Esse retorno, como você pode ver na linha 16, é um objeto com os três métodos que declarei no módulo:
 
- `depositar`: para enviar dinheiro para a conta
- `sacar`: para remover dinheiro da conta
- `verSaldo`: para ver o valor da conta no momento
 
Então da linha 19 em diante, eu apenas deposito e saco valores aleatórios. Também uso o console para saber como andam as contas.
 
O ponto principal é que o `saldo` da conta, que declarei na linha 2 é privado. Isso quer dizer que não é possível alterá-lo diretamente após iniciar a `contaCorrente`. Para isso, é preciso usar os métodos `depositar` e `sacar`.
 
O último caso de uso é mais raro, mas ainda assim é interessante conhecer.
 
### Minificação
 
Minificar é remover tudo aquilo que "sobra" em um código.
 
Coisas que "sobram" geralmente são:
 
- Espaços em branco
- Quebras de linha
- Variáveis com nomes longos
- Ponto e vírgula desnecessários
- Parênteses ou chaves desnecessários
- Etc
 
Aqui, o foco é nas **variáveis com nomes longos**. Veja o código abaixo:
 
```javascript
(function (w, d) {
  // corpo da IIFE
})(window, document);
```
 
Dentro do corpo da IIFE, a variável `w` representa `window`, e `d` representa `document`. Porém com menos caracteres.
 
É claro que esse exemplo é minúsculo e até dificulta a leitura do código. Porém algumas bibliotecas usam essa técnica para gerar um código final menor. Eles não usam esse código durante o desenvolvimento.
 
E aí, conseguiu ter uma noção do que é uma IIFE? 😬
 
## Callback
 
Para usar uma função, você precisa declará-la e depois executá-la.
 
Você pode até executar uma função *antes* de declarar ela, por causa do [hoisting](https://developer.mozilla.org/pt-BR/docs/Glossary/Hoisting).
 
O hoisting é como se o Javascript colocasse as declarações de funções no início do arquivo antes de começar a executar.
 
Assim, o Javascript salva elas na memória antes de tudo e não ocorre erro de `Uncaught ReferenceError: myFunction is not defined`.
 
Uma função invocada imediatamente faz essas duas etapas de uma vez.
 
Para criar uma IIFE, declare uma função normal dentro de um parênteses, e acrescente outro ao final. O segundo parênteses serve para enviar argumentos para a IIFE:
 
```javascript
(function(mensagem) {
  console.log(mensagem);
})('Uma IIFE');
```
 
As principais vantagens de criar uma IIFE são:
 
1. Evitar o conflito variáveis através do encapsulamento
2. Manter a imutabilidade ao usar os parâmetros
 
Outras vantagens que você encontrar podem ser variações dessas duas.
 
Use uma expressão de função autoinvocada para:
 
- Proteger variáveis do escopo global
- Inicializar pequenos trechos da aplicação
- Criar módulos
- Minificar código
 
Você também pode chamar uma IIFE com os parênteses da execução dentro do primeiro. Não faz diferença. Vai a gosto do cliente:
 
```javascript
// Opção que expliquei ao longo do artigo

(function() {
  var result = true;
  return result;
})(); // <<< aqui

// Outra opção

(function() {
  var result = true;
  return result;
}()); // <<< aqui
```
 
Obrigado pela sua leitura. Deixe um comentário aqui abaixo se ficou alguma dúvida. Será um prazer trocar uma ideia e te ajudar 😬
 
Continue estudando:
 
- [https://mariusschulz.com/blog/use-cases-for-javascripts-iifes](https://mariusschulz.com/blog/use-cases-for-javascripts-iifes)
- [https://developer.mozilla.org/pt-BR/docs/Glossary/IIFE](https://developer.mozilla.org/pt-BR/docs/Glossary/IIFE)
- [https://udn.realityripple.com/docs/Glossary/IIFE](https://udn.realityripple.com/docs/Glossary/IIFE)
- [https://maxroecker.github.io/blog/javascript-intermediario-5/](https://maxroecker.github.io/blog/javascript-intermediario-5/)
- [https://dev.to/cristuker/javascript-o-que-sao-funcoes-iife-2d4e](https://dev.to/cristuker/javascript-o-que-sao-funcoes-iife-2d4e)
- [https://imasters.com.br/front-end/sobre-funcoes-imediatas-javascript-iife](https://imasters.com.br/front-end/sobre-funcoes-imediatas-javascript-iife)
- [https://www.mundojs.com.br/2019/01/30/expressoes-de-funcao-imediatamente-invocadas-iife/](https://www.mundojs.com.br/2019/01/30/expressoes-de-funcao-imediatamente-invocadas-iife/)