Tudo o que você precisa saber sobre IIFEs

5 minuto(s) de leitura

IIFE é um conceito frequentemente utilizado por desenvolvedores, mesmo que não saibam exatamente como ele funciona ou porque tem que ser feito assim. A explicação é simples, mas iremos por partes.

IIFE é a sigla para Immediately-invoked function expression, que em português seria mais ou menos como Expressão de Função Imediatamente Invocada. Ou seja, é uma função que, assim que criada, é executada.

Ela é utilizada principalmente para evitar o Hoisting dentro de blocos, evitar a poluição de variáveis com escopo global e também para que possamos criar variáveis e funções privadas, com funções públicas para lidar com elas.

Como Funciona?

Para entender melhor esse conceito, primeiro devemos saber que o Javascript diferencia todas as instruções de códigos como expressão (expression) ou declaração (statement). Qualquer código que retorne um resultado é considerado como uma expressão, enquanto que estruturas condicionais ou de repetição são instruções declarativas (statement). Por exemplo:

var a = 1,
    x = 0

if(a > 0) {         // Statement
    x = a + 2       // Expression
}

O if não retorna nenhum resultado, apenas altera o fluxo de execução do programa. Mas, para que ele faça isso, ele precisa validar uma expression. Então, ele espera o resultado dessa expression, para só depois decidir qual caminho o programa deverá tomar. Em resumo, poderíamos dizer que um statement é uma instrução que altera a ordem padrão de execução do código (de cima pra baixo) e uma expression, qualquer instrução que gere um resultado, mesmo que nulo.

E porque é útil saber isso para entender o IIFE? O motivo disso é que dependendo da forma como criamos uma função, o Javascript pode tratá-la como um statement ou uma expression.

E quando uma função é considerada um statement? Justamente quando a declaramos no código, criando-a da forma padrão:

function somaUm(x) {
    return x + 1;
}

Ela é considerada um statement nesse caso porque nós estamos apenas declarando-a para usar depois. Se tentássemos executá-la como abaixo, passando como parâmetro o valor 10, daria um erro:

function somaUm(x) {
    return x + 1;
}(10)

Isso acontece porque executá-la assim seria o mesmo que fazer:

function somaUm(x) {
    return x + 1;
}

(10)  // SyntaxError: Unexpected token )

Perceba inclusive que o erro trata de um “)” colocado no lugar errado, o erro não menciona nada da tentativa de se executar um statement.

E quando uma função é considerada uma expression? Um dos casos é quando vamos invocá-las. A função é uma expression nesse caso pois nesse momento o interpretador realmente espera que ela retorne algum valor, mesmo que isso não aconteça.

Então, para conseguirmos executar uma função assim que a criarmos, é necessário primeiro fazer com que o interpretador pense que ela seja uma expression! E como fazemos isso? Colocando-a entre parênteses.

(function somaUm(x) {
    return x + 1;
})

Isso é possível pois dentro de parênteses só é possível colocarmos expressions. Por isso que o código abaixo nunca poderia funcionar:

(if(1 < 2) console.log("Não funciona"))

Pois o if sempre será considerado como um statement. Quando uma função é tratada como uma expression, ela pode ser executada. E é por isso que uma IIFE funciona. Depois que a função estiver dentro de parênteses, basta invocá-la, passando o parâmetro que quiser:

(function somaUm(x) {
    return x + 1;
})(10)

Mas se o parênteses obriga que dentro dele exista apenas expressions, os operadores +, -, *, /, !, = e new também. Quando realizamos alguma operação aritmética, é necessário que façamos com pelo menos uma expressão ou dois valores. Não tem como somar 1 + if. Isso quer dizer que, se colocarmos uma função logo depois de um sinal de + por exemplo, ela também será considerada uma expression. É por isso que os códigos abaixo são perfeitamente válidos, apesar de serem menos utilizados:

+function () { console.log("Olá Mundo!")}()
-function () { console.log("Olá Mundo!")}()
*function () { console.log("Olá Mundo!")}()
/function () { console.log("Olá Mundo!")}()
!function () { console.log("Olá Mundo!")}()

var meuNome = function () { return "Thiago" }()

new function () { console.log("Olá Mundo!")}()

Outra coisa que é necessário explicar é que nós podemos criar IIFEs com funções anônimas, que é o mais comum, mas também podemos criá-las com funções nomeadas, conforme mostrei nos exemplos. A grande diferença é que quando criamos IIFEs com funções nomeadas, nós poderemos utilizar o nome para fazer chamadas recursivas, o que já não seria possível com uma função anônima:

var fazerFatorial = function fatorial(x) {
    if (x == 0)
        return 1
    return x * fatorial(x - 1)
}

console.log(fatorial(5))        // fatorial is not defined
console.log(fazerFatorial(5))   // 120

Nesse exemplo de função comum, vemos que o nome que damos à função só pode ser utilizado dentro dela. Fora do escopo devemos utilizar a variável à qual ela foi atribuida. O mesmo aconteceria com uma IIFE.

No próximo artigo, pretendo mostrar como evitar o hoisting de variáveis sem a necessidade de utilizar a técnica IIFE, e alguns outros truques do ECMAScript 6+.

Até mais!

Deixe um comentário