Qual é o objective do Node.js module.exports e como você o usa?

Qual é o objective do Node.js module.exports e como você o usa?

Não consigo encontrar nenhuma informação sobre isso, mas parece ser uma parte bastante importante do Node.js, como muitas vezes vejo no código-fonte.

De acordo com a documentação do Node.js :

módulo

Uma referência ao module atual. Em particular module.exports é o mesmo que o object de exportação. Veja src/node.js para mais informações.

Mas isso não ajuda muito.

O que exatamente o module.exports faz e como seria um exemplo simples?

module.exports é o object que é realmente retornado como resultado de uma chamada require .

A variável exports é inicialmente configurada para o mesmo object (ou seja, é um atalho “alias”), portanto, no código do módulo, você normalmente escreveria algo assim:

 var myFunc1 = function() { ... }; var myFunc2 = function() { ... }; exports.myFunc1 = myFunc1; exports.myFunc2 = myFunc2; 

para exportar (ou “expor”) as funções com escopo interno myFunc1 e myFunc2 .

E no código de chamada você usaria:

 var m = require('./mymodule'); m.myFunc1(); 

onde a última linha mostra como o resultado de require é (geralmente) apenas um object simples cujas propriedades podem ser acessadas.

NB: se você sobrescrever as exports , não mais se referirá a module.exports . Então, se você deseja atribuir um novo object (ou uma referência de function) às exports , você também deve atribuir esse novo object a module.exports


Vale a pena observar que o nome incluído no object de exports não precisa ser o mesmo nome do escopo interno do módulo para o valor que você está adicionando, portanto, você poderia ter:

 var myVeryLongInternalName = function() { ... }; exports.shortName = myVeryLongInternalName; // add other objects, functions, as required 

Seguido por:

 var m = require('./mymodule'); m.shortName(); // invokes module.myVeryLongInternalName 

Isso já foi respondido, mas eu queria adicionar alguns esclarecimentos …

Você pode usar as duas exports e module.exports para importar o código para seu aplicativo da seguinte forma:

var mycode = require('./path/to/mycode');

O caso de uso básico que você verá (por exemplo, no código de exemplo do ExpressJS) é que você define propriedades no object de exports em um arquivo .js que, em seguida, é importado usando require()

Então, em um exemplo de contagem simples, você poderia ter:

(counter.js):

 var count = 1; exports.increment = function() { count++; }; exports.getCount = function() { return count; }; 

… então no seu aplicativo (web.js, ou realmente qualquer outro arquivo .js):

 var counting = require('./counter.js'); console.log(counting.getCount()); // 1 counting.increment(); console.log(counting.getCount()); // 2 

Em termos simples, você pode pensar em arquivos necessários como funções que retornam um único object, e você pode adicionar propriedades (cadeias de caracteres, números, matrizes, funções, qualquer coisa) ao object retornado, definindo-as nas exports .

Às vezes, você desejará que o object retornado de uma chamada require() seja uma function que você possa chamar, em vez de apenas um object com propriedades. Nesse caso, você também precisa definir module.exports , assim:

(sayhello.js):

 module.exports = exports = function() { console.log("Hello World!"); }; 

(app.js):

 var sayHello = require('./sayhello.js'); sayHello(); // "Hello World!" 

A diferença entre exportações e module.exports é explicada melhor nesta resposta aqui .

Observe que o mecanismo do módulo NodeJS é baseado em módulos CommonJS que são suportados em muitas outras implementações como RequireJS , mas também SproutCore , CouchDB , Wakanda , OrientDB , ArangoDB , RingoJS , TeaJS , SilkJS , curl.js ou até mesmo Adobe Photoshop (via PSLib ). Você pode encontrar a lista completa de implementações conhecidas aqui .

A menos que seu módulo use módulos ou resources específicos do nó, eu o encorajo fortemente usando exports vez de module.exports que não fazem parte do padrão CommonJS e, em sua maioria, não são suportados por outras implementações.

Outro recurso específico do NodeJS é quando você atribui uma referência a um novo object às exports vez de apenas adicionar propriedades e methods a ele, como no último exemplo fornecido pelo Jed Watson neste encadeamento. Eu pessoalmente desencorajaria essa prática, pois isso quebra o suporte de referência circular do mecanismo de módulos do CommonJS. Então, ele não é suportado por todas as implementações e o exemplo de Jed deve então ser escrito dessa maneira (ou similar) para fornecer um módulo mais universal:

(sayhello.js):

 exports.run = function() { console.log("Hello World!"); } 

(app.js):

 var sayHello = require('./sayhello'); sayHello.run(); // "Hello World!" 

Ou usando resources do ES6

(sayhello.js):

 Object.assign(exports, { // Put all your public API here sayhello() { console.log("Hello World!"); } }); 

(app.js):

 const { sayHello } = require('./sayhello'); sayHello(); // "Hello World!" 

PS: Parece que o Appcelerator também implementa módulos CommonJS, mas sem o suporte de referência circular (consulte: Módulos Appcelerator e CommonJS (armazenamento em cache e referências circulares) )

Algumas poucas coisas você deve tomar cuidado se você atribuir uma referência a um novo object para exports e / ou modules.exports :

1. Todas as propriedades / methods previamente anexados às exports originais ou module.exports são naturalmente perdidos porque o object exportado agora referencia outro novo

Esse é óbvio, mas se você adicionar um método exportado no início de um módulo existente, certifique-se de que o object nativo exportado não esteja referenciando outro object no final

 exports.method1 = function () {}; // exposed to the original exported object exports.method2 = function () {}; // exposed to the original exported object module.exports.method3 = function () {}; // exposed with method1 & method2 var otherAPI = { // some properties and/or methods } exports = otherAPI; // replace the original API (works also with module.exports) 

2. No caso de uma das exports ou module.exports referenciar um novo valor, eles não fazem referência ao mesmo object mais

 exports = function AConstructor() {}; // override the original exported object exports.method2 = function () {}; // exposed to the new exported object // method added to the original exports object which not exposed any more module.exports.method3 = function () {}; 

3. Consequência complicada. Se você alterar a referência para as exports e module.exports , é difícil dizer qual API está exposta (parece que module.exports ganha)

 // override the original exported object module.exports = function AConstructor() {}; // try to override the original exported object // but module.exports will be exposed instead exports = function AnotherConstructor() {}; 

a propriedade module.exports ou o object exports permite que um módulo selecione o que deve ser compartilhado com o aplicativo

insira a descrição da imagem aqui

Eu tenho um vídeo em module_export disponível aqui

Ao dividir seu código de programa em vários arquivos, module.exports é usado para publicar variables ​​e funções para o consumidor de um módulo. A chamada require() em seu arquivo de origem é substituída pelo module.exports correspondente carregado a partir do módulo.

Lembre-se quando escrever módulos

  • Carregamentos de módulos são armazenados em cache, somente a chamada inicial avalia JavaScript.
  • É possível usar variables ​​locais e funções dentro de um módulo, nem tudo precisa ser exportado.
  • O object module.exports também está disponível como taquigrafia de exports . Mas ao retornar uma única function, use sempre module.exports .

diagrama de exportações do módulo

De acordo com: “Módulos Parte 2 – Módulos de Escrita” .

o link de referência é assim:

 exports = module.exports = function(){ //.... } 

as propriedades das exports ou module.exports , como funções ou variables, serão expostas fora

Há algo que você deve prestar mais atenção: não override exportações.

porque ?

porque exporta apenas a referência de module.exports, você pode adicionar as propriedades nas exportações, mas se você replace as exportações, o link de referência será quebrado.

bom exemplo :

 exports.name = 'william'; exports.getName = function(){ console.log(this.name); } 

mau exemplo :

 exports = 'william'; exports = function(){ //... } 

Se você quer apenas expor apenas uma function ou variável, assim:

 // test.js var name = 'william'; module.exports = function(){ console.log(name); } // index.js var test = require('./test'); test(); 

este módulo apenas expõe uma function e a propriedade do nome é privada para o exterior.

Existem alguns módulos padrão ou existentes no node.js quando você faz o download e instala o node.js como http, sys etc.

Como eles já estão em node.js, quando queremos usar esses módulos, basicamente gostamos de módulos de importação , mas por quê? porque eles já estão presentes no node.js. A importação é como tirá-los do node.js e colocá-los no seu programa. E então usando eles.

Considerando que Exports é exatamente o oposto, você está criando o módulo que você quer, digamos que o module addition.js e colocando esse módulo no node.js, você o faz exportando-o.

Antes de escrever qualquer coisa aqui, lembre-se, module.exports.additionTwo é o mesmo que exports.additionTwo

Huh, então essa é a razão, nós gostamos

 exports.additionTwo = function(x) {return x+2;}; 

Tenha cuidado com o caminho

Vamos dizer que você criou um módulo addition.js,

 exports.additionTwo = function(x){ return x + 2; }; 

Quando você executar isso no seu prompt de comando NODE.JS:

 node var run = require('addition.js'); 

Isso vai errar dizendo

Erro: Não é possível encontrar o módulo addition.js

Isso ocorre porque o processo node.js não consegue o addition.js, já que não mencionamos o caminho. Então, nós podemos definir o caminho usando NODE_PATH

 set NODE_PATH = path/to/your/additon.js 

Agora, isso deve ser executado com sucesso, sem erros!

Só mais uma coisa, você também pode executar o arquivo addition.js não configurando o NODE_PATH, de volta ao seu prompt de comando nodejs:

 node var run = require('./addition.js'); 

Já que estamos fornecendo o caminho aqui dizendo que está no diretório atual ./ isso também deve ser executado com sucesso.

Um módulo encapsula o código relacionado em uma única unidade de código. Ao criar um módulo, isso pode ser interpretado como mover todas as funções relacionadas em um arquivo.

Suponha que haja um arquivo Hello.js que inclua duas funções

 sayHelloInEnglish = function() { return "Hello"; }; sayHelloInSpanish = function() { return "Hola"; }; 

Nós escrevemos uma function somente quando a utilidade do código é mais do que uma chamada.

Suponha que queremos aumentar a utilidade da function para um arquivo diferente, digamos World.js, neste caso exportando um arquivo que pode ser obtido por module.exports.

Você pode exportar apenas a function pelo código dado abaixo

 var anyVariable={ sayHelloInEnglish = function() { return "Hello"; }; sayHelloInSpanish = function() { return "Hola"; }; } module.export=anyVariable; 

Agora você só precisa exigir o nome do arquivo no World.js para poder usar essas funções

 var world= require("./hello.js"); 

A intenção é:

A programação modular é uma técnica de design de software que enfatiza a separação da funcionalidade de um programa em módulos independentes e intercambiáveis, de modo que cada um contém tudo o que é necessário para executar apenas um aspecto da funcionalidade desejada.

Wikipedia

Eu imagino que torna-se difícil escrever um grande programa sem código modular / reutilizável. Em nodejs podemos criar programas modulares utilizando module.exports definindo o que expomos e compomos com o nosso programa require .

Tente este exemplo:

fileLog.js

 function log(string) { require('fs').appendFileSync('log.txt',string); } module.exports = log; 

stdoutLog.js

 function log(string) { console.log(string); } module.exports = log; 

program.js

 const log = require('./stdoutLog.js') log('hello world!'); 

executar

$ node program.js

Olá Mundo!

Agora tente trocar ./stdoutLog.js por ./fileLog.js .

Qual é o propósito de um sistema de módulos?

Realiza as seguintes coisas:

  1. Mantém nossos arquivos de inchaço para tamanhos realmente grandes. Ter arquivos com, por exemplo, 5000 linhas de código geralmente é muito difícil de lidar durante o desenvolvimento.
  2. Impede a separação de preocupações. Ter nosso código dividido em vários arquivos nos permite ter nomes de arquivo apropriados para cada arquivo. Desta forma, podemos identificar facilmente o que cada módulo faz e onde encontrá-lo (assumindo que fizemos uma estrutura de diretórios lógica que ainda é sua responsabilidade).

Ter módulos facilita a localização de determinadas partes do código, o que torna nosso código mais fácil de manter.

Como funciona?

NodejS usa o sistema de módulo CommomJS, que funciona da seguinte maneira:

  1. Se um arquivo deseja exportar algo, ele deve declará-lo usando a syntax module.export
  2. Se um arquivo deseja importar alguma coisa, ele deve declará-lo usando a syntax require('file')

Exemplo:

test1.js

 const test2 = require('./test2'); // returns the module.exports object of a file test2.Func1(); // logs func1 test2.Func2(); // logs func2 

test2.js

 module.exports.Func1 = () => {console.log('func1')}; exports.Func2 = () => {console.log('func2')}; 

Outras coisas úteis para saber:

  1. Módulos estão ficando em cache . Quando você está carregando o mesmo módulo em 2 arquivos diferentes, o módulo só precisa ser carregado uma vez. A segunda vez que um require() é chamado no mesmo módulo, ele é retirado do cache.
  2. Módulos são carregados em síncrono . Esse comportamento é necessário, se fosse asynchronous, não poderíamos acessar o object recuperado de require() imediatamente.