module.exports vs exports no Node.js

Eu encontrei o seguinte contrato em um módulo Node.js:

module.exports = exports = nano = function database_module(cfg) {...} 

Eu me pergunto o que é o diferente entre module.exports e as exports e porque ambos são usados ​​aqui.

Definir module.exports permite que a function database_module seja chamada como uma function, quando required . Simplesmente definir exports não permitiria que a function fosse exportada porque o nó exporta o module.exports object. module.exports referências. O código a seguir não permite que o usuário chame a function.

module.js

O seguinte não funcionará.

 exports = nano = function database_module(cfg) {return;} 

O seguinte irá funcionar se module.exports estiver definido.

 module.exports = exports = nano = function database_module(cfg) {return;} 

console

 var func = require('./module.js'); // the following line will **work** with module.exports func(); 

Basicamente, node.js não exporta o object que as exports atualmente referenciam, mas exporta as propriedades daquilo que as exports originalmente fazem referência. Embora o Node.js exporte as referências do module.exports , permitindo chamá-lo como uma function.


2º motivo menos importante

Eles definem module.exports e exports para garantir que as exports não estejam referenciando o object exportado anteriormente. Ao definir ambos, você usa as exports como uma forma abreviada e evita erros potenciais mais tarde.

Usando exports.prop = true vez de module.exports.prop = true salva caracteres e evita confusão.

Mesmo que a pergunta tenha sido respondida e aceita há muito tempo, eu só quero compartilhar meus 2 centavos:

Você pode imaginar que no início do seu arquivo há algo como (apenas para explicação):

 var module = new Module(...); var exports = module.exports; 

insira a descrição da imagem aqui

Portanto, faça o que fizer, tenha em mente que module.exports e NOT exports serão retornados de seu módulo quando você precisar desse módulo em algum outro lugar.

Então, quando você faz algo como:

 exports.a = function() { console.log("a"); } exports.b = function() { console.log("b"); } 

Você está adicionando 2 funções ‘a’ e ‘b’ ao object no qual module.exporta pontos também, então o typeof do resultado retornado será um object : { a: [Function], b: [Function] }

É claro que este é o mesmo resultado que você obterá se estiver usando module.exports neste exemplo em vez de exports .

Esse é o caso em que você deseja que seu módulo se expanda como um contêiner de valores exportados. Considerando que, se você deseja apenas exportar uma function construtora, então, há algo que você deve saber sobre o uso de module.exports ou exports ; (Lembre-se novamente que module.exports será retornado quando você precisar de algo, não exportar).

 module.exports = function Something() { console.log('bla bla'); } 

Agora typeof retornando resultado é 'function' e você pode exigir isso e invocar imediatamente como:
var x = require('./file1.js')(); porque você sobrescreve o resultado retornado para ser uma function.

No entanto, usando as exports você não pode usar algo como:

 exports = function Something() { console.log('bla bla'); } var x = require('./file1.js')(); //Error: require is not a function 

Como com as exports , a referência não “aponta” mais para o object no qual module.exports aponta, portanto, não há mais uma relação entre exports e module.exports . Neste caso, module.exports ainda aponta para o object vazio {} que será retornado.

A resposta aceita de outro tópico também deve ajudar: O Javascript passa por referência?

Basicamente, a resposta está no que realmente acontece quando um módulo é requerido via declaração require . Assumindo que esta é a primeira vez que o módulo está sendo requerido.

Por exemplo:

 var x = require('file1.js'); 

conteúdo de file1.js:

 module.exports = '123'; 

Quando a instrução acima é executada, um object Module é criado. Sua function construtora é:

 function Module(id, parent) { this.id = id; this.exports = {}; this.parent = parent; if (parent && parent.children) { parent.children.push(this); } this.filename = null; this.loaded = false; this.children = []; } 

Como você vê, cada object do módulo tem uma propriedade com exports nome. Isso é o que é retornado como parte de require .

O próximo passo de require é envolver o conteúdo de file1.js em uma function anônima, como abaixo:

 (function (exports, require, module, __filename, __dirname) { //contents from file1.js module.exports = '123; }); 

E esta function anônima é invocada da seguinte maneira, module aqui se refere ao object Module criado anteriormente.

 (function (exports, require, module, __filename, __dirname) { //contents from file1.js module.exports = '123; }) (module.exports,require, module, "path_to_file1.js","directory of the file1.js"); 

Como podemos ver dentro da function, o argumento formal de exports se refere a module.exports . Em essência, é uma conveniência fornecida ao programador do módulo.

No entanto, essa conveniência precisa ser exercida com cuidado. Em qualquer caso, ao tentar atribuir um novo object às exportações, garantimos que o façamos desta maneira.

 exports = module.exports = {}; 

Se fizermos isso seguindo o caminho errado , module.exports ainda estará apontando para o object criado como parte da instância do módulo.

 exports = {}; 

Como resultado, adicionar qualquer coisa ao object de exportação acima não afetará o object module.exports e nada será exportado ou retornado como parte de require.

Inicialmente, module.exports=exports e a function require retorna o object module.exports refere-se a.

se adicionarmos propriedade ao object, digamos exports.a=1 , então module.exports e exports ainda se referem ao mesmo object. Portanto, se chamarmos require e atribuirmos o módulo a uma variável, a variável terá uma propriedade ae seu valor será 1;

Mas se replacemos um deles, por exemplo, exports=function(){} , então eles são diferentes agora: exports refere-se a um novo object e module.exports se refere ao object original. E se precisarmos do arquivo, ele não retornará o novo object, já que module.exports não se refere ao novo object.

Para mim, vou continuar adicionando nova propriedade, ou replace os dois para um novo object. Apenas replace um não está certo. E tenha em mente que module.exports é o verdadeiro chefe.

exports e module.exports são os mesmos, a menos que você reatribuir as exports dentro do seu módulo.

A maneira mais fácil de pensar sobre isso é pensar que essa linha está implicitamente no topo de cada módulo.

 var exports = module.exports = {}; 

Se, dentro do seu módulo, você reatribuir exports , então você o reatribui dentro de seu módulo e não é mais igual a module.exports . É por isso que, se você deseja exportar uma function, você deve fazer:

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

Se você simplesmente atribuísse sua function() { ... } às exports , você estaria reatribuindo as exports para não mais apontar para module.exports .

Se você não quer se referir a sua function por module.exports toda vez, você pode fazer:

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

Observe que module.exports é o argumento mais à esquerda.

Anexar propriedades às exports não é o mesmo, pois você não está reatribuindo. É por isso que isso funciona

 exports.foo = function() { ... } 

JavaScript passa objects por cópia de uma referência

É uma diferença sutil a ver com a forma como os objects são passados ​​por referência em JavaScript.

exports e module.exports ambos apontam para o mesmo object. exports é uma variável e module.exports é um atributo do object module.

Digamos que eu escreva algo assim:

 exports = {a:1}; module.exports = {b:12}; 

exports e module.exports agora apontam para objects diferentes. A modificação de exportações não modifica mais o module.exports.

Quando a function de importação inspeciona module.exports , obtém {b:12}

Acabei de fazer algum teste, acontece que, dentro do código do módulo do nodejs, deveria ser algo assim:

 var module.exports = {}; var exports = module.exports; 

assim:

1:

 exports = function(){}; // this will not work! as it make the exports to some other pointer module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export. 

2:

 exports.abc = function(){}; // works! exports.efg = function(){}; // works! 

3: mas, enquanto neste caso

 module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports. module.exports.a = 'value a'; // works exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later) 

Aqui está uma boa descrição escrita sobre módulos de nó em node.js no livro de ação da publicação Manning .
O que finalmente é exportado em sua aplicação é module.exports.
exports é configurado simplesmente como uma referência global para module.exports , que inicialmente é definida como um object vazio ao qual você pode adicionar propriedades. Então exports.myFunc é apenas uma abreviação de module.exports.myFunc .

Como resultado, se as exportações estiverem configuradas para qualquer outra coisa, elas quebrarão a referência entre module.exports e exports . Como o module.exports é o que realmente é exportado, as exportações não funcionarão mais como o esperado – ele não faz referência ao módulo .exporta mais. Se você quiser manter esse link, poderá tornar module.exports as exportações de referência novamente da seguinte forma:

 module.exports = exports = db; 

Eu passei por alguns testes e acho que isso pode lançar alguma luz sobre o assunto …

app.js :

 var ... , routes = require('./routes') ...; ... console.log('@routes', routes); ... 

versões de /routes/index.js :

 exports = function fn(){}; // outputs "@routes {}" exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }" module.exports = function fn(){}; // outputs "@routes function fn(){}" module.exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }" 

Eu até adicionei novos arquivos:

./routes/index.js :

 module.exports = require('./not-index.js'); module.exports = require('./user.js'); 

./routes/not-index.js :

 exports = function fn(){}; 

./routes/user.js :

 exports = function user(){}; 

Nós obtemos a saída “@routes {}”


./routes/index.js :

 module.exports.fn = require('./not-index.js'); module.exports.user = require('./user.js'); 

./routes/not-index.js :

 exports = function fn(){}; 

./routes/user.js :

 exports = function user(){}; 

Obtemos a saída “@routes {fn: {}, user: {}}”


./routes/index.js :

 module.exports.fn = require('./not-index.js'); module.exports.user = require('./user.js'); 

./routes/not-index.js :

 exports.fn = function fn(){}; 

./routes/user.js :

 exports.user = function user(){}; 

Obtemos a saída “@routes {user: [Function: user]}” Se mudarmos user.js para { ThisLoadedLast: [Function: ThisLoadedLast] } , obtemos a saída “@routes {ThisLoadedLast: [Function: ThisLoadedLast]} “.


Mas se nós modificarmos ./routes/index.js

./routes/index.js :

 module.exports.fn = require('./not-index.js'); module.exports.ThisLoadedLast = require('./user.js'); 

./routes/not-index.js :

 exports.fn = function fn(){}; 

./routes/user.js :

 exports.ThisLoadedLast = function ThisLoadedLast(){}; 

… obtemos “@routes {fn: {fn: [Função: fn]}, ThisLoadedLast: {ThisLoadedLast: [Função: ThisLoadedLast]}}”

Por isso sugiro sempre usar module.exports nas suas definições de módulo.

Eu não entendo completamente o que está acontecendo internamente com o Node, mas, por favor, comente se você pode fazer mais sentido, pois tenho certeza que isso ajuda.

– Codificação feliz

Isso mostra como require() funciona na sua forma mais simples, extraída do Eloquent JavaScript

Problema Não é possível para um módulo exportar diretamente um valor diferente do object de exportação, como uma function. Por exemplo, um módulo pode querer exportar apenas o construtor do tipo de object que ele define. No momento, ele não pode fazer isso porque require sempre usa o object de exports criado como o valor exportado.

Solução Fornece módulos com outra variável, module , que é um object que possui uma propriedade exports . Inicialmente, essa propriedade aponta para o object vazio criado por require, mas pode ser sobrescrito com outro valor para exportar outra coisa.

 function require(name) { if (name in require.cache) return require.cache[name]; var code = new Function("exports, module", readFile(name)); var exports = {}, module = {exports: exports}; code(exports, module); require.cache[name] = module.exports; return module.exports; } require.cache = Object.create(null); 

Aqui está o resultado de

 console.log("module:"); console.log(module); console.log("exports:"); console.log(exports); console.log("module.exports:"); console.log(module.exports); 

insira a descrição da imagem aqui

Além disso:

 if(module.exports === exports){ console.log("YES"); }else{ console.log("NO"); } //YES 

Nota: A especificação CommonJS permite apenas o uso da variável exports para expor membros públicos. Portanto, o padrão de exportações nomeadas é o único que é realmente compatível com a especificação CommonJS. O uso de module.exports é uma extensão fornecida pelo Node.js para suportar um intervalo mais amplo de padrões de definição de módulo.

 var a = {},md={}; 

// Primeiro, as exportações e module.exports apontam o mesmo object vazio

 exp = a;//exports =a; md.exp = a;//module.exports = a; exp.attr = "change"; console.log(md.exp);//{attr:"change"} 

// Se você apontar exp para outro object em vez de apontar sua propriedade para outro object. O md.exp será object vazio {}

 var a ={},md={}; exp =a; md.exp =a; exp = function(){ console.log('Do nothing...'); }; console.log(md.exp); //{} 

Dos docs

A variável exports está disponível no escopo de nível de arquivo de um módulo e recebe o valor de module.exports antes de o módulo ser avaliado.

Ele permite um atalho, para que module.exports.f = … possa ser escrito de forma mais sucinta como exports.f = …. No entanto, esteja ciente de que, como qualquer variável, se um novo valor é atribuído às exportações, é não está mais ligado a module.exports:

É apenas uma variável apontando para module.exports.

Achei esse link útil para responder à pergunta acima.

http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/

Para adicionar as outras mensagens O sistema de módulos no nó não

 var exports = module.exports 

antes de executar seu código. Então, quando você quer export = foo, você provavelmente quer fazer module.exports = exports = foo mas usando exports.foo = foo deve ficar bem

“Se você quiser que a raiz da exportação do seu módulo seja uma function (como um construtor) ou se você deseja exportar um object completo em uma atribuição em vez de criá-la uma propriedade de cada vez, atribua-a a module.exports em vez de exportações “. – http://nodejs.org/api/modules.html

1.exports -> use como utilitário singleton
2. module-exports -> use como objects lógicos como serviço, modelo etc

Vamos criar um módulo com 2 maneiras:

Mão única

 var aa = { a: () => {return 'a'}, b: () => {return 'b'} } module.exports = aa; 

Segunda maneira

 exports.a = () => {return 'a';} exports.b = () => {return 'b';} 

E é assim que require () irá integrar o módulo.

Primeira maneira:

 function require(){ module.exports = {}; var exports = module.exports; var aa = { a: () => {return 'a'}, b: () => {return 'b'} } module.exports = aa; return module.exports; } 

Segunda maneira

 function require(){ module.exports = {}; var exports = module.exports; exports.a = () => {return 'a';} exports.b = () => {return 'b';} return module.exports; } 

no nó js o arquivo module.js é usado para executar o sistema module.load.nodo em que o nó executa um arquivo que contém o conteúdo do arquivo js como segue

 '(function (exports, require, module, __filename, __dirname) {',+ //your js file content '\n});' 

por causa deste encapsulamento dentro do código-fonte do ur js você pode acessar as exportações, requer, módulo, etc. esta abordagem é usada porque não há outra maneira de obter funcionalidades escritas no arquivo js para outro.

então o node executa esta function envolvida usando c ++. Nesse momento, o object de exportação que passou para essa function será preenchido.

você pode ver dentro desta function parâmetros export e módulo. na verdade, as exportações são um membro público da function de construtor do módulo.

veja o código a seguir

Copie este código para b.js

 console.log("module is "+Object.prototype.toString.call(module)); console.log("object.keys "+Object.keys(module)); console.log(module.exports); console.log(exports === module.exports); console.log("exports is "+Object.prototype.toString.call(exports)); console.log('----------------------------------------------'); var foo = require('a.js'); console.log("object.keys of foo: "+Object.keys(foo)); console.log('name is '+ foo); foo(); 

Copie este código para a.js

 exports.name = 'hello'; module.exports.name = 'hi'; module.exports.age = 23; module.exports = function(){console.log('function to module exports')}; //exports = function(){console.log('function to export');} 

Agora execute usando o nó

esta é a saída

 module is [object Object] object.keys id,exports,parent,filename,loaded,children,paths {} true 

exports é [object Object]

object.keys de foo: nome é function () {console.log (‘function para módulo de exportações’)} function para módulo de exportação

Agora remova a linha comentada em a.js e comente a linha acima dessa linha e remova a última linha de b.js e execute.

no mundo javascript você não pode reatribuir object que passou como parâmetro, mas você pode alterar membro público da function quando o object dessa function definida como um parâmetro para outra function

lembre-se

use module.exports e somente se você quiser obter uma function quando usar require keyword. no exemplo acima, var foo = require (a.js); você pode ver que podemos chamar foo como uma function;

é assim que a documentação do nó explica isso “O object exports é criado pelo sistema Module. Às vezes isso não é aceitável, muitos querem que seu módulo seja uma instância de alguma class. Para isso, designe o object exportado desejado para module.exports.”

  1. Ambos module.exports e exports apontam para a mesma function database_module(cfg) {...} .

     1| var a, b; 2| a = b = function() { console.log("Old"); }; 3| b = function() { console.log("New"); }; 4| 5| a(); // "Old" 6| b(); // "New" 

    Você pode alterar b na linha 3 para a , a saída é inversa. A conclusão é:

    b são independentes.

  2. Então module.exports = exports = nano = function database_module(cfg) {...} é equivalente a:

     var f = function database_module(cfg) {...}; module.exports = f; exports = f; 

    Assumindo que o acima é o module.js , que é requerido pelo foo.js Os benefícios de module.exports = exports = nano = function database_module(cfg) {...} estão claros agora:

    • Em foo.js , já que module.exports é require('./module.js') :

       var output = require('./modules.js')(); 
    • Em moduls.js : Você pode usar as exports vez de module.exports .

Então, você ficará feliz se as duas exports e module.exports apontarem para a mesma coisa.

porque ambos são usados ​​aqui

Eu acredito que eles só querem deixar claro que module.exports , exports e nano apontam para a mesma function – permitindo que você use qualquer variável para chamar a function dentro do arquivo. nano fornece algum contexto para o que a function faz.

exports não serão exportadas (apenas module.exports ), então por que se preocupar em sobrescrevê- module.exports também?

O trade-off de verbosidade limita o risco de erros futuros, como usar exports vez de module.exports dentro do arquivo. Também fornece esclarecimentos de que module.exports e exports estão de fato apontando para o mesmo valor.


module.exports vs exports

Contanto que você não reatribua module.exports ou exports (e, em vez disso, adicione valores ao object ao qual ambos se referem), você não terá problemas e poderá usar as exports com segurança para ser mais conciso.

Ao atribuir a um não-object, eles estão apontando para locais diferentes que podem ser confusos, a menos que você deseje que module.exports seja algo específico (como uma function).

Definir as exports para um não-object não faz muito sentido, pois você terá que definir module.exports = exports no final para poder usá-lo em outros arquivos.

 let module = { exports: {} }; let exports = module.exports; exports.msg = 'hi'; console.log(module.exports === exports); // true exports = 'yo'; console.log(module.exports === exports); // false exports = module.exports; console.log(module.exports === exports); // true module.exports = 'hello'; console.log(module.exports === exports); // false module.exports = exports; console.log(module.exports === exports); // true 

Por que atribuir module.exports a uma function?

Mais conciso! Compare quanto mais curto o segundo exemplo é:

helloWorld1.js: module.exports.hello = () => console.log('hello world');

app1.js: let sayHello = require('./helloWorld1'); sayHello.hello; // hello world let sayHello = require('./helloWorld1'); sayHello.hello; // hello world

helloWorld2.js: module.exports = () => console.log('hello world');

app2.js: let sayHello = require('./helloWorld2'); sayHello; // hello world let sayHello = require('./helloWorld2'); sayHello; // hello world