Node.js - Entendendo alguns tipos de módulos

Tipo de módulos - Node.js

Se você já programou com Node.js deve conhecer como criar 1 módulo nele, correto?

Uma dica:

module.exports

Até aí tudo bem né?

Vamos explorar

Então vamos começar a explorar o mundo selvagem dos módulos fazendo algo simples: uma função que recebe 1 Array e retorna 1 Array com seus valores elevados ao quadrado.

function quadrado (array) {  
  return array.map(function(a,b){
    return Math.pow(a,2)
  })
}

Como também poderia ser escrita assim:

function quadrado (array) {  
  return array.map(function(a,b){
    return a * a
  })
}

Tudo bem a função é simples:

  • itero sobre o array, criando 1 Array novo com o valor modificado de cada posição
  • retorno o Array novo

Então vamos testar no console do Node.js:

(Tipos-de-modulos) ➜ () ➜ node
> function quadrado (array) {
...   return array.map(function(a,b){
.....     return Math.pow(a,2)
.....   })
... }
undefined  
> 
> quadrado([1,2,3,4])
[ 1, 4, 9, 16 ]

Perfeito! Agora vamos entender as formas diferentes de se modularizar isso no Node.js, primeiramente faremos o mais básico:

function quadrado (array) {  
  return array.map(function(a,b){
    return Math.pow(a,2)
  })
}

module.exports = quadrado  

Muito simples né?

E a forma de utilizá-lo também é igualmente simples, index.js:

const quadrado = require('./quadrado')  
const valores = [1,2,3,4]  
console.log(quadrado(valores))  

Entenda que estamos jogando o conteúdo de:

function quadrado (array) {  
  return array.map(function(a,b){
    return Math.pow(a,2)
  })
}

Em const quadrado, por isso podemos chamar quadrado(valores).

Agora basta executar o index.js:

(Tipos-de-modulos) ➜ () ➜ node index.js
[ 1, 4, 9, 16 ]

Você deve pensar:

Ah tio mas é porque tem o mesmo nome da função né?

Interessante pensamento, porém deixe eu lhe mostrar alguns exemplos para você tirar sua própria conclusão.

Exemplo 1:

const quadrado = (array) => {  
  return array.map(function(a,b){
    return Math.pow(a,2)
  })
}
module.exports = quadrado  

Exemplo 2:

module.exports = (array) => {  
  return array.map(function(a,b){
    return Math.pow(a,2)
  })
}

Executando esses 2 módulos da mesma forma recebemos a mesma saída:

(Tipos-de-modulos) ➜ () ➜ node index.js
[ 1, 4, 9, 16 ]

Logo você deve ter notado que o importante é o nome da variável que recebe o módulo, por exemplo:

const valores = [1,2,3,4]  
const nomeDOIDO = require('./quadrado')  
console.log(nomeDOIDO(valores))  

Vai retornar a mesma coisa que anteriormente, por isso muito cuidado ao nomear suas variáveis que recebem módulos externos!

E se você quisesse que o módulo do quadrado só funcionasse se fosse iniciado com o Array a ser modificado?

Via código fica mais fácil de entender:

function quadrado (array) {  
  return array.map(function(a,b){
    return Math.pow(a,2)
  })
}

module.exports = (valores) => quadrado  

Agora se formos executar o mesmo arquivo, index.js, veremos a seguinte saída:

(Tipos-de-modulos) ➜ () ➜ node index.js
[Function: quadrado]

Percebeu que apenas uma pequena modificação pode mudar tudo?

Agora para utilizar esse módulo devemos fazer o seguinte:

const valores = [1,2,3,4]  
const quadrado = require('./quadrado')(valores)  
console.log(quadrado)  

Executando o index.js veremos o seguinte:

(Tipos-de-modulos) ➜ () ➜ node index.js
[ 1, 4, 9, 16 ]

Tudo irá depender da sua necessidade, porém dessa forma se você quiser utilizar a funcionalidade do módulo mais de 1 vez no arquivo onde você está importando terá que chamar sempre assim:

require('./quadrado')(valores)  

Sem instanciar a função em nenhuma variável porque isso sempre irá lhe retornar o resultado.

Tenha muito cuidado!

Agora vamos ver uma forma diferente de exportar uma função, como construtora:

const quadrado = require('./quadrado')

function calculadora () {  
  this.quadrado = quadrado
}
module.exports = calculadora  

Agora perceba se eu tentar utilizar esse módulo assim:

const valores = [1,2,3,4]  
const Calculadora = require('./calculadora')  
console.log(Calculadora.quadrado(valores))  

Receberei o seguinte erro:

(Tipos-de-modulos) ➜ () ➜ node index.js
/Users/jeancarlonascimento/www/projetos/nomadev/posts/modularizacao/Tipos-de-modulos/index.js:4
console.log(Calculadora.quadrado(valores))  
                        ^

TypeError: Calculadora.quadrado is not a function  
    at Object.<anonymous> (/Users/jeancarlonascimento/www/projetos/nomadev/posts/modularizacao/Tipos-de-modulos/index.js:4:25)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Function.Module.runMain (module.js:575:10)
    at startup (node.js:160:18)
    at node.js:456:3

SHIT!!!!

Então vamos ver o que temos em Calculadora:

(Tipos-de-modulos) ➜ () ➜ node index.js
[Function: calculadora]

Bom se sabemos que é uma função e para criar uma instância nova de uma função usamos o new, basta fazer isso:

const valores = [1,2,3,4]  
const Calculadora = require('./calculadora')  
const calc = new Calculadora()  
console.log(calc.quadrado(valores))  

Pois dessa forma você pode estender seu módulo adicionando funções assim:

const valores = [1,2,3,4]  
const Calculadora = require('./calculadora')

Calculadora.prototype.somar = (a, b) => {  
  return a + b
};

const calc = new Calculadora()  
console.log(calc.quadrado(valores))  
console.log(calc.somar(2, 3))  

Legal né?

Mas até agora só trabalhamos com funções e como fica com OBJETOS?

OMFG

Olhe que tranquilo no mamilo:

const quadrado = require('./quadrado')

const calculadora = {  
  quadrado
}
module.exports = calculadora  

E para usar:

const valores = [1,2,3,4]  
const Calculadora = require('./calculadora')  
console.log(Calculadora.quadrado(valores))  

E para adicionar funções:

const valores = [1,2,3,4]  
const Calculadora = require('./calculadora')

Calculadora.somar = (a, b) => {  
  return a + b
};

console.log(Calculadora.quadrado(valores))  
console.log(Calculadora.somar(2, 3))  

Suave na nave, né?

Muito suave

Bom fica aí mais uma dica do tio Suissa.

ps: a diferença entre module.exports e exports fica para um próximo artigo.

Comentários

comments powered by Disqus