IIFE (immediately invoked function expression) é um design pattern que consiste em uma função executada imediatamente após sua definição. Esse termo foi popularizado pelo Ben Alman, antigamente chamava-se self-executing anonymous function, ou self-invoked anonymous function.
Como vimos no artigo Function Declaration vs Function Expression existem algumas formas de se declarar funções usando a palavra chave
function
.Quando o statement começa com a palavra
function
, a engine Javascript entende que trata-se de uma function declaration, o que não é o caso aqui, logo, precisamos forçar a engine a tratar essa linha como uma expression, por isso usamos !
. Funciona com qualquer operador unário (+,-, ~, etc..)!function() { alert('function IIFE') }()
Também podemos forçar a função a ser tratada como uma expression usando a palavra chave
void
.void function() { console.log('IIFE') }()
Esses são padrões menos comuns de serem vistos quando implementando IIFE's, e dessa forma, também não conseguimos atribuir o valor de retorno das funções à uma variável.
O modelo mais comumente é encapsular a função entre parênteses e então atribuir essa expression a uma variável.
const result = (function() { return 1 }()); console.log(result) // Output: 1
Também podemos omitir o parênteses pois já estamos definindo uma function expression. Porém dificulta a legibilidade do código pois não sugere ao desenvolvedor que trata-se de uma IIFE, sem que este navegue e visualize a última linha da função.
const result = function() { return 1 }(); console.log(result) // Output: 1
Usos
Antes do ES6, não existiam módulos de forma nativa na especificação da linguagem, e funções eram a única forma de criar um escopo privado - ver Function Scope, Block Scope and Lexical Scope.
Esse era um design pattern muito usado para evitar poluir o escopo global, já que também não existiam
const
e let
, e o block scope.(function() { var scoped = 1; }()); console.log(scoped); // ReferenceError
Outro uso muito comum era o module pattern, que permitia simular o conceito de classes, de tal forma que fosse possível incluir variáveis e métodos públicos e privados, protegendo algumas partes do código do escopo superior.
Na época não existia o conceito de privacidade no Javascript, pois não era possível definir variáveis e métodos privados como em outras linguagens, logo era preciso criar um outro escopo para simular esse comportamento.
var module = (function() { // variável acessível apenas dentro da IIFE var counter = 0; function increment() { counter++; } // API pública return { increment: increment } }()); var counter = module() counter.increment()
Por fim, quando se era necessário usar um loop for, por exemplo, uma IIFE também era necessária.
for (var i = 0; i < 2; i++) { const button = document.createElement('button'); button.innerText = 'Button ' + i; button.onclick = function() { console.log(i); }; document.body.appendChild(button); } console.log(i); // 2
Ao clicar nos dois botões o mesmo alerta é disparado:
2
, pois a variável i
é global, e seu último valor foi 2
. Para corrigir esse problema antes do ES6, uma IIFE era usadafor (var i = 0; i < 2; i++) { const button = document.createElement('button'); button.innerText = 'Button ' + i; button.onclick = (function(copyOfI) { return () => { console.log(copyOfI); }; })(i); document.body.appendChild(button); } console.log(i); // 2