O Padrão Revealing Module no Javascript
Tags: javascript, node
Published: 2020-06-20 00:14:38

> Essa é uma tradução de um [gist](https://gist.github.com/zcaceres/bb0eec99c02dda6aac0e041d0d4d7bf2) escrito por Zach Caceres.

Javascript não tem os especificadores `private` e `public` das linguagens orientadas a objeto mais tradicionais como C# ou Java. Contudo, você pode conseguir o mesmo efeito através da aplicação inteligente do escopo a nível de função do Javascript.

O princípio central do padrão Revealing Module é que todas as funcionalidades e variáveis devem ser ocultadas, a menos que deliberadamente expostas.

Vamos imaginar que nós temos um aplicativo de música onde um arquivo `musicPlayer.js` manipula grande parte da experiência do usuário. Precisamos acessar alguns métodos, mas não devemos mexer com outros métodos ou variáveis.

#### Usando Escopo de Função para Criar Métodos Públicos e Privados

Vamos primeiro ver como o escopo a nível de função do Javascript pode nos ajudar a criar métodos públicos e privados.

Podemos mover todas as funcionalidades para dentro de um escopo de função. Depois, retornamos um objeto com as funções que gostaríamos que fossem acessíveis em outros arquivos.

```js
// musicPlayerModule.js

var musicPlayer = function () {
  // Vamos garantir que ninguém possa acessar diretamente nossa songList
  var songList = ['California Girls', 'California Dreaming', 'Hotel California'];  

  // Nós vamos expor todas essas funções para o usuários
  function play () {
    console.log('Im playing the next song!');
  }

  function pause () {
    console.log('Im paused!');
  }

  function addTrackToMusicQueue (track) {
    songList.push(track);
    console.log('I added a song');
  }

  function showNextTrack () {
    console.log('My next track is', songList[0]);
  }

  // Vamos ocultar essa função
  function loadSong() {
    filesystem.loadNextSong();
  }

  return {
    playMusic: play,
    pauseMusic: pause,
    showNextTrack: showNextTrack,
    addTrack: addTrackToMusicQueue
  }
}

const musicModule = musicPlayer(); // Chama nossa musicPlayer para retornar seu objeto (módulo)
musicModule.playMusic(); // 'Im playing the next song!'
musicModule.pauseMusic(); // 'I'm paused!'
musicModule.showNextTrack(); // 'The next track is California Girls'

// Coisas que não podemos acessar...
musicModule.loadSong(); // error: not a function
musicModule.songList.push('White Rabbit'); // undefined error
```

Agora, podemos acessar todos os métodos que nós precisamos em nosso objeto `musicModule`. Mas, não podemos mexer no nosso `songList` ou acessar o método `loadSong()`. Ambos são privados.

Isso funciona bem. Mas há um grande problema.

Estamos usando `musicPlayer` como um namespace para manter nossas funções. Mas espere, nosso `musicPlayer` é uma função que ainda está exposta ao escopo global!

Alguém poderia aparecer e invocá-lo novamente, criando um novo `musicPlayer`. Então, teríamos várias instância de `musicPlayer` flutuando, poluindo nosso ambiente e causando todo tipo de confusão.

#### Ocultando Seu Módulo com uma IIFE

A melhor maneira de evitar a exposição de sua função top-level ao escopo global é agrupar tudo em uma IIFE. Uma IIFE é uma immediately-invoked function expression (expressão de função chamada imediatamente). É um nome e tanto. Significa apenas que nós chamamos (invocamos) essa função assim que o arquivo é executado (imediatamente). 

Como nossa função não tem nome, nós a chamamos de expressão. Como não tem nome, nunca pode ser invocado em outro lugar.

Veja como fica:

```js
var musicModule = (function () {
  // Vamos garantir que ninguém possa acessar diretamente nossa songList
  var songList = ['California Girls', 'California Dreaming', 'Hotel California'];  

  // Nós vamos expor todas essas funções para o usuários
  function play () {
    console.log('Im playing the next song!');
  }

  function pause () {
    console.log('Im paused!');
  }

  function addTrackToMusicQueue (track) {
    songList.push(track);
    console.log('I added a song');
  }

  function showNextTrack () {
    console.log('My next track is', songList[0]);
  }

  // Vamos ocultar essa função
  function loadSong() {
    filesystem.loadNextSong();
  }

  return {
    playMusic: play,
    pauseMusic: pause,
    showUpNext: showNextTrack,
    addTrack: addTrackToMusicQueue
  }
})(); // Nossa função IIFE (cercada por parênteses) é chamada aqui

musicModule.playMusic(); // 'Im playing the next song!'
musicModule.pauseMusic(); // 'I'm paused!'
musicModule.showUpNext(); // 'The next track is California Girls'
musicModule.loadSong(); // error: not a function
musicModule.songList.push('White Rabbit'); // undefined
```
Nosso escopo a nível de função ainda mantém nossos métodos e variáveis pública e privadas, com base em se os expomos no objeto de retorno.

Mas dessa vez, nós evitamos o risco de podermos invocar nosso módulo em outro lugar no nosso código.

Em outros arquivo nós podemos agora usar as funcionalidades de `musicModule` - Um módulo bem encapsulado em nosso escopo global!