Go to English Blog

Design Patterns no JavaScript – Module

Leia em 2 minutos

Design Patterns é um assunto recorrente de todas as linguagens. Vou começar uma nova série de artigos sobre eles aplicados no JavaScript. E este primeiro artigo irá falar sobre o pattern Module.

O Module Pattern é muito utilizado porque ele permite organizar melhor o código, sem expor variáveis globais de modo promíscuo. Como ainda não temos uma sintaxe de módulos do próprio JavaScript, usamos os módulos para garantir que o escopo de variáveis seja fechado, além de simular a privacidade de atributos e funções.

Este pattern pode envolver uma combinação de diversas técnicas como closures e funções auto-executáveis. A sintaxe é bastante característica e pode ser encontrada facilmente em diversas bibliotecas.

(function(){
  // your code here
})();

No JavaScript, funções são apenas objetos. E, por esse motivo, pode ser atribuídas em variáveis. Nesse nosso caso, estamos pulando o passo de atribuição e executamos a função imediatamente após sua definição. Como definir uma função anônima e executá-la não é uma sintaxe válida, precisamos englobá-la com os parênteses (embora seja possível fazer algumas gambiarras para permitir isso).

 function(){}();   // SyntaxError: Unexpected token (
+function(){}();   // Executes the function
-function(){}();   // Executes the function

Existe uma variação desta sintaxe que adiciona os parentêses de execução dentro dos parênteses da expressão.

(function(){
  // your code here
}());

Como o JavaScript ainda não possui módulos nativamente (embora isso provavelvemente entre na versão ECMAScript 6, também chamada de Harmony), este pattern é muito utilizado para simular módulos. Isso só é possível por causa do escopo local de variáveis de uma função, que permite isolar tudo o que é feito dentro da função.

É muito comum, por exemplo, usarmos o Module Pattern para criar plugins do jQuery, pois passamos o objeto jQuery como dependência e atribuímos a uma variável com um nome melhor, normalmente $.

(function($){
  // your plugin here
})(jQuery);

A ideia é bastante simples. Funções podem ser executadas e receber parâmetros. Nesse caso, estamos executando uma função anônima e passando o parâmetro jQuery. Na função anônima podemos receber os parâmetros que foram passados durante a execução. Como não existe nenhuma obrigatoriedade de mantermos o mesmo nome, podemos atribuí-la à variável $.

Como variáveis definidas em uma função tem escopo local, podemos usar o Module Pattern para simular privacidade de atributos.

var Counter = {
    count: 0
  , increment: function() {
      return this.count += 1;
    }
};

Counter.increment();
Counter.increment();
Counter.count; // returns 2
Counter.count = 100;
Counter.count; // returns 100

O grande problema dessa implementação é que é muito simples quebrar o encapsulamento e manipular o atributo Counter.count diretamente. Em vez disso, podemos criar uma variável local que irá armazenar o contador e expor uma interface pública que retorna esse valor.

var Counter = (function(){
  var count = 0;

  return {
      count: function() {
        return count;
      }

    , increment: function() {
        return count += 1;
      }
  };
})();

Note que ambas as funções referenciam a variável count, que não pode ser acessada diretamente de fora da função auto-executável. Dessa forma, podemos encapsular todo o comportamento, sem termos que nos preocupar com modificações feitas sem ser pela função Counter.increment().

Essa técnica de retornar uma interface pública à partir de um módulo também é chamada de Revealing Module Pattern.

Finalizando

Enquanto ainda não temos módulos nativamente, o Module Pattern é bastante útil e ajuda bastante nesta tarefa. A implementação de módulos diretamente na linguagem vai ajudar bastante já que a sintaxe é muito mais simples e direta.

No próximo artigo iremos ver um pouco sobre o Singleton Pattern.