Desmontando o Nome
A sigla IIFE diz exatamente o que faz:
- Invoked — chamada/executada
- Function Expression — uma função escrita como expressão (não declaração)
snippetJavaScript
// Função normal — você define, depois chamafunction greet() { console.log("Olá!");}greet(); // Você tem que chamar // Um IIFE — roda imediatamente, sem chamar(function() { console.log("Olá!");})(); // Roda na hora!
Expressão vs Statement: Por Que Isso Importa para IIFEs
Para entender IIFEs, você precisa entender a diferença entre expressões e statements no JavaScript.
snippettext
┌─────────────────────────────────────────────────────────────────────┐│ EXPRESSÃO vs STATEMENT ││ ││ EXPRESSÃO = produz um valor ││ ───────────────────────────── ││ 5 + 3 → 8 ││ "hello" → "hello" ││ myFunction() → o que a função retornar ││ x > 10 → true ou false ││ function() {} → um valor de função (em posição de expressão) ││ ││ STATEMENT = executa uma ação (sem valor produzido) ││ ────────────────────────────────────────────────── ││ if (x > 10) { } → controla fluxo, sem valor ││ for (let i...) { } → loops, sem valor ││ function foo() { } → declara função, sem valor ││ let x = 5; → declara variável, sem valor │└─────────────────────────────────────────────────────────────────────┘
A função pode ser escrita de duas formas:
snippetJavaScript
// FUNCTION DECLARATION (statement)function greet() { return "Hello!";} // FUNCTION EXPRESSION (expression)const greet = function() { return "Hello!";};
Arrow functions são sempre expressões:
snippetJavaScript
const greet = () => "Hello!";
Por que isso importa para IIFEs?
snippetJavaScript
// ✗ Isso FALHA — JavaScript vê "function" e espera declaraçãofunction() { console.log("Isso causa erro de sintaxe!");}(); // SyntaxError: Function statements require a function name // ✓ Isso FUNCIONA — parênteses transformam em expressão(function() { console.log("Isso funciona!");})(); // Os parênteses dizem ao JavaScript: "Isso é um valor, não uma declaração"
| Característica | Declaração | Expressão |
|---|
| Sintaxe | function name() {} | const name = function() {} |
| Hoisting | Sim (pode chamar antes) | Não (precisa definir primeiro) |
| Nome | Obrigatório | Opcional |
| Uso em IIFE | Não | Sim (precisa de parênteses) |
A Anatomia de um IIFE
snippetJavaScript
(function() { // seu código aqui})(); // Vamos rotular cada parte: ( function() { ... } ) ();│ │ ││ │ └─── 3. Invoca (chama) imediatamente│ ││ └─────── 2. Envolve em parênteses (vira expressão)│└──────────────────────────── 1. Define uma função
Por que os parênteses? Sem eles, JavaScript acha que você está escrevendo uma declaração de função, não uma expressão. Os parênteses dizem: "Isso é um valor (expressão), não um statement."
Variações de IIFE
snippetJavaScript
// Estilo clássico(function() { console.log("IIFE clássico");})(); // Parênteses alternativos(function() { console.log("Estilo alternativo");}()); // Arrow function IIFE (moderno)(() => { console.log("Arrow IIFE");})(); // Com parâmetros((name) => { console.log(`Olá, ${name}!`);})("Alice"); // IIFE nomeado (útil para debug)(function myIIFE() { console.log("IIFE nomeado");})();
Por Que IIFEs Foram Inventadas?
Antes dos módulos ES6, JavaScript tinha um problema grande: tudo era global. Quando scripts eram carregados com tags comuns, variáveis declaradas com var fora de funções viravam globais e eram compartilhadas entre todos os scripts da página:
snippetJavaScript
// file1.jsvar userName = "Alice"; // var cria variáveis globaisvar count = 0; // file2.js (carregado depois de file1.js)var userName = "Bob"; // Ops! Sobrescreve o primeiro userNamevar count = 100; // Ops! Sobrescreve o primeiro count // Agora o código de file1.js quebrou porque suas variáveis foram substituídas
IIFEs resolveram isso criando escopo privado:
snippetJavaScript
// file1.js — envolvido em IIFE(function() { var userName = "Alice"; // Privado a este IIFE var count = 0; // Privado a este IIFE // Seu código aqui...})(); // file2.js — também envolvido em IIFE(function() { var userName = "Bob"; // Variável diferente, sem conflito! var count = 100; // Variável diferente, sem conflito! // Seu código aqui...})();
Exemplo Prático: Criando Variáveis Privadas
Um dos usos mais poderosos de IIFEs é criar variáveis privadas inacessíveis de fora:
snippetJavaScript
const counter = (function() { // Variável privada — não pode ser acessada diretamente let count = 0; // Função privada — também escondida function log(message) { console.log(`[Counter] ${message}`); } // Retorna interface pública return { increment() { count++; log(`Incrementado para ${count}`); }, decrement() { count--; log(`Decrementado para ${count}`); }, getCount() { return count; } };})(); // Usando o countercounter.increment(); // [Counter] Incrementado para 1counter.increment(); // [Counter] Incrementado para 2console.log(counter.getCount()); // 2 // Tentando acessar variáveis privadasconsole.log(counter.count); // undefined (é privado!)counter.log("test"); // TypeError: counter.log is not a function
Esse padrão é chamado Module Pattern. Usa closures para manter variáveis privadas. Era a forma padrão de criar "módulos" antes do ES6.
IIFE com Parâmetros
snippetJavaScript
// Passando jQuery para garantir que $ seja jQuery(function($) { $(".button").click(function() { console.log("Clicado!"); });})(jQuery); // Passando window e document por performance(function(window, document) { const body = document.body; const location = window.location;})(window, document);
Quando Usar IIFEs Hoje
Com módulos ES6, IIFEs são menos comuns. Mas ainda são úteis para:
1. Código de inicialização única
snippetJavaScript
const config = (() => { const env = process.env.NODE_ENV; const apiUrl = env === 'production' ? 'https://api.example.com' : 'http://localhost:3000'; return { env, apiUrl };})();
2. Criar IIFEs assíncronos
snippetJavaScript
// Top-level await nem sempre está disponível(async () => { const response = await fetch('/api/data'); const data = await response.json(); console.log(data);})();
3. Evitar poluição global em scripts
snippetJavaScript
// Em uma tag <script> (não módulo)(function() { const secretKey = "abc123"; window.MyApp = { init() { /* ... */ } };})();