web-dev-qa-db-fra.com

module.exports vs exports dans Node.js

J'ai trouvé le contrat suivant dans un module Node.js:

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

Je me demande quelle est la différence entre module.exports et exports et pourquoi les deux sont utilisés ici.

665
Andreas Köberle

La définition de module.exports permet à la fonction database_module d'être appelée comme une fonction lorsque requiredname__. Définir simplement exportsne permettrait pas à la fonction d'être exportée car le noeud exporte les références de l'objet module.exports. Le code suivant ne permettrait pas à l'utilisateur d'appeler la fonction.

module.js

Ce qui suit ne fonctionnera pas.

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

Ce qui suit fonctionnera si module.exports est défini.

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

console

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

En gros, node.js n'exporte pas l'objet que exportsréférence actuellement, mais exporte les propriétés de ce que exportsfait référence à l'origine. Bien que Node.js exporte l'objet module.exports références, ce qui vous permet de l'appeler comme une fonction.


2e raison la moins importante

Ils définissent à la fois module.exports et exportspour s'assurer que exportsne fait pas référence à l'objet exporté antérieur. En définissant les deux, vous utilisez le nom exportset évitez les bugs potentiels ultérieurement.

Utiliser exports.prop = true au lieu de module.exports.prop = true enregistre les caractères et évite la confusion.

399
William A

Même si la question a été répondue et acceptée il y a longtemps, je veux juste partager mes 2 centimes:

Vous pouvez imaginer qu'au tout début de votre fichier, il y a quelque chose comme (juste pour des explications):

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

enter image description here

Ainsi, quoi que vous fassiez, gardez simplement à l'esprit que module.exports et NOT exportsseront retournés par votre module lorsque vous aurez besoin de ce module ailleurs.

Alors, quand tu fais quelque chose comme:

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

Vous ajoutez 2 fonctions 'a' et 'b' à l'objet sur lequel module.exports pointe également, de sorte que typeofle résultat renvoyé sera un objectname__: { a: [Function], b: [Function] }

Bien entendu, vous obtiendrez le même résultat si vous utilisez module.exports dans cet exemple au lieu de exportsname__.

C'est le cas où vous voulez que votre module.exports se comporte comme un conteneur de valeurs exportées. Par contre, si vous souhaitez uniquement exporter une fonction constructeur, vous devez savoir comment utiliser module.exports ou exportsname __; (rappelez-vous que module.exports sera renvoyé lorsque vous aurez besoin de quelque chose que de ne pas exporter).

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

Maintenant, typeof retournant le résultat est 'function' et vous pouvez l'exiger et l'invoquer immédiatement comme:
var x = require('./file1.js')(); car vous écrasez le résultat renvoyé par une fonction.

Cependant, avec exportsname__, vous ne pouvez pas utiliser quelque chose comme:

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

Parce que, avec exportsname__, la référence ne "pointe" plus sur l'objet où module.exports est pointé, il n'y a donc plus de relation entre exportset module.exports. Dans ce cas, module.exports pointe toujours sur l'objet vide {} qui sera renvoyé.

Une réponse acceptée sur un autre sujet devrait également aider: Est-ce que Javascript passe par référence?

437
Srle

Fondamentalement, la réponse réside dans ce qui se passe réellement lorsqu'un module est requis via l'instruction require. En supposant que ce soit la première fois que le module est requis.

Par exemple:

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

contenu de file1.js:

module.exports = '123';

Lorsque l'instruction ci-dessus est exécutée, un objet Module est créé. Sa fonction constructeur est:

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 = [];
}

Comme vous le voyez, chaque objet de module a une propriété nommée exports. C'est ce qui est finalement retourné dans le cadre de require.

La prochaine étape de require consiste à envelopper le contenu de file1.js dans une fonction anonyme comme ci-dessous:

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

Et cette fonction anonyme est invoquée de la manière suivante, module fait ici référence à l’objet Module créé précédemment.

(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");

Comme on peut le voir à l'intérieur de la fonction, l'argument formel exports fait référence à module.exports. Essentiellement, c'est une commodité fournie au programmeur de module.

Cependant, cette commodité doit être exercée avec précaution. Dans tous les cas, si vous essayez d'affecter un nouvel objet à des exportations, assurez-vous que vous procédez ainsi.

exports = module.exports = {};

Si nous le faisons de la manière suivante mauvais sens, module.exports sera toujours pointé sur l'objet créé dans le cadre de l'instance de module.

exports = {};

En conséquence, ajouter quoi que ce soit à l'objet exports ci-dessus n'aura aucun effet sur l'objet module.exports et rien ne sera exporté ni renvoyé dans le cadre de require.

201
Chandu

Initialement, module.exports=exports et la fonction require renvoie l'objet auquel module.exports fait référence.

si nous ajoutons une propriété à l'objet, disons exports.a=1, alors module.exports et exports toujours font référence au même objet. Donc, si nous appelons require et assignons le module à une variable, alors la variable a une propriété a et sa valeur est 1;

Mais si nous substituons l'un d'eux, par exemple, exports=function(){}, alors ils sont différent maintenant: exports se réfère à un nouvel objet et module.exports se réfère à l'objet d'origine. Et si nous avons besoin du fichier, il ne retournera pas le nouvel objet, puisque module.exports n'est pas référencé au nouvel objet.

Pour moi, je continuerai à ajouter une nouvelle propriété ou à les remplacer par un nouvel objet. Juste remplacer un n'est pas juste. Et gardez à l'esprit que module.exports est le vrai patron.

76
cameron

exportset module.exports sont identiques, sauf si vous réaffectez exportsdans votre module.

La façon la plus simple d’y penser est de penser que cette ligne est implicitement au sommet de chaque module.

var exports = module.exports = {};

Si, dans votre module, vous réaffectez exportsname__, vous le réaffectez dans votre module et il n'est plus égal à module.exports. C'est pourquoi, si vous voulez exporter une fonction, vous devez faire:

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

Si vous affectiez simplement votre function() { ... } à exportsname__, vous réaffecteriez exportspour qu'il ne pointe plus sur module.exports.

Si vous ne voulez pas faire référence à votre fonction par module.exports à chaque fois, vous pouvez faire:

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

Notez que module.exports est l'argument le plus à gauche.

L'association de propriétés à exportsn'est pas la même, car vous ne la réaffectez pas. C'est pourquoi cela fonctionne

exports.foo = function() { ... }
46
dustin.schultz

JavaScript transmet les objets par copie d'une référence

C'est une différence subtile à faire avec la façon dont les objets sont passés par référence en JavaScript.

exports et module.exports désignent tous deux le même objet. exports est une variable et module.exports est un attribut de l'objet module.

Dites que j'écris quelque chose comme ceci:

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

exports et module.exports pointent maintenant vers différents objets. La modification des exportations ne modifie plus module.exports.

Lorsque la fonction d'importation inspecte module.exports, elle obtient {b:12}

24
superluminary

Je viens de faire un test, il s'avère que, dans le code du module de nodejs, il devrait ressembler à ceci:

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

alors:

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: mais alors que dans ce cas

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)
11
Lyman Lai

Voici une bonne description écrite sur les modules de nœud dans node.js en action book from Manning publication.
Ce qui est finalement exporté dans votre application est module.exports.
exportations
 est mis en place simplement comme une référence globale à module.exports , qui est initialement défini comme un objet vide auquel vous pouvez ajouter des propriétés. Alors exports.myFunc est juste un raccourci pour module.exports.myFunc.

En conséquence, si exportations est réglé sur autre chose, il casse le référence entre module.exports et exportations . Parce que module.exports est ce qui est vraiment exporté, exportations ne fonctionnera plus comme prévu - cela ne fait pas référence module .exports plus. Si vous voulez maintenir ce lien, vous pouvez faire module.exports référence exportations à nouveau comme suit:

module.exports = exports = db;
9
Salar

J'ai passé des tests et je pense que cela pourrait nous éclairer sur le sujet ...

app.js:

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

versions 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] }"

J'ai même ajouté de nouveaux fichiers:

./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(){};

Nous obtenons le résultat "@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(){};

Nous obtenons le résultat "@routes {fn: {}, utilisateur: {}}"


./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(){};

Nous obtenons la sortie "@routes {utilisateur: [Fonction: utilisateur]}" si nous remplaçons user.js par { ThisLoadedLast: [Function: ThisLoadedLast] }, nous obtenons la sortie "@routes {ThisLoadedLast: [Fonction: ThisLoadedLast]}".


Mais si on modifie ./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(){};

... nous obtenons "@routes {fn: {fn: [Fonction: fn]}, ThisLoadedLast: {ThisLoadedLast: [Fonction: ThisLoadedLast]}}"

Je suggère donc de toujours utiliser module.exports dans les définitions de vos modules.

Je ne comprends pas tout à fait ce qui se passe en interne avec Node, mais veuillez commenter si vous pouvez donner plus de sens à cela car je suis sûr que cela aide.

- codage heureux

6
Cody

Voici le résultat de

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

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

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

enter image description here

Également:

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

//YES

Remarque: La spécification CommonJS autorise uniquement l'utilisation de la variable exports pour exposer les membres publics. Par conséquent, le modèle d'exportations nommé est le seul qui soit réellement compatible avec la spécification CommonJS. L'utilisation de module.exports est une extension fournie par Node.js pour prendre en charge une gamme plus étendue de modèles de définition de module.

3
serkan
var a = {},md={};

// Tout d'abord, les exports et module.exports pointent le même objet vide

exp = a;//exports =a;
md.exp = a;//module.exports = a;

exp.attr = "change";

console.log(md.exp);//{attr:"change"}

// Si vous pointez exp sur un autre objet au lieu de pointer sa propriété sur un autre objet. Le md.exp sera un objet vide {}

var a ={},md={};
exp =a;
md.exp =a;

exp = function(){ console.log('Do nothing...'); };

console.log(md.exp); //{}
3
Anson Hwang

J'ai trouvé ce lien utile pour répondre à la question ci-dessus.

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

Pour ajouter aux autres postes Le système de module dans le noeud ne

var exports = module.exports 

avant d'exécuter votre code. Donc, quand vous voulez exports = foo, vous voudrez probablement faire module.exports = exports = foo mais utiliser exports.foo = foo devrait convenir

3
Sudhir Srinivasan

Cela montre comment require() fonctionne dans sa forme la plus simple, extraite de Eloquent JavaScript

Problème Il n'est pas possible pour un module d'exporter directement une valeur autre que l'objet exports, telle qu'une fonction. Par exemple, un module peut vouloir exporter uniquement le constructeur du type d'objet qu'il définit. Pour le moment, il ne peut pas le faire car require utilise toujours l'objet exports qu'il crée en tant que valeur exportée.

Solution Fournissez aux modules une autre variable, module, qui est un objet doté d'une propriété exports. Cette propriété pointe initialement sur l'objet vide créé par require, mais peut être remplacée par une autre valeur afin d'exporter autre chose.

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);
3
onmyway133

De la docs

La variable exports est disponible dans la portée de niveau fichier d'un module et se voit attribuer la valeur module.exports avant que le module ne soit évalué.

Il permet un raccourci pour que module.exports.f = ... puisse être écrit plus succinctement sous exports.f = .... Cependant, Sachez que, comme toute variable, si une nouvelle valeur est affectée à exports, elle n'est plus liée à module.exports:

C'est juste une variable pointant sur module.exports.

3
ANewGuyInTown

"Si vous souhaitez que la racine de l'exportation de votre module soit une fonction (un constructeur, par exemple) ou si vous souhaitez exporter un objet complet dans une affectation au lieu de la construire propriété par propriété, affectez-le à module.exports au lieu de exportations." - http://nodejs.org/api/modules.html

2
Bob KaKoO

Créons un module de 2 manières:

Une manière

var aa = {
    a: () => {return 'a'},
    b: () => {return 'b'}
}

module.exports = aa;

Deuxième façon

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

Et voici comment require () va intégrer le module.

Première manière:

function require(){
    module.exports = {};
    var exports = module.exports;

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

    return module.exports;
}

Deuxième façon

function require(){
    module.exports = {};
    var exports = module.exports;

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

    return module.exports;
}
1
Dmitry Sergeev

1.exports -> utiliser comme utilitaire singleton
2. module-exports -> utiliser comme objets logiques tels que service, modèle, etc.

1
riv

enter image description here

Chaque fichier que vous créez est un module. module est un objet. Il a la propriété appelée exports : {} qui est un objet vide par défaut.

vous pouvez créer des fonctions/middlewares et ajouter à cet objet d'export vide tel que exports.findById() => { ... } puis require n'importe où dans votre application et utiliser ...

controllers/user.js

exports.findById = () => {
    //  do something
}

nécessite dans routes.js d'utiliser:

const {findyId} = './controllers/user'
0
Ryan Dhungel
  1. module.exports et exportspointent vers le même 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"
    

    Vous pouvez remplacer bsur la ligne 3 par aname__, la sortie est inversée. La conclusion est:

    aet bsont indépendants.

  2. Donc, module.exports = exports = nano = function database_module(cfg) {...} est équivalent à:

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

    Supposons que ce qui précède est module.js, requis par foo.js. Les avantages de module.exports = exports = nano = function database_module(cfg) {...} sont clairs:

    • Dans foo.js, puisque module.exports est require('./module.js'):

      var output = require('./modules.js')();
      
    • Dans moduls.js: Vous pouvez utiliser exportsau lieu de module.exports.

Vous serez donc heureux si exportset module.exports pointent vers la même chose.

module.exports et exports les deux pointent sur le même objet avant l'évaluation du module.

Toute propriété que vous ajoutez à l'objet module.exports sera disponible lorsque votre module sera utilisé dans un autre module à l'aide de l'instruction require. exports est un raccourci disponible pour la même chose. Par exemple:

module.exports.add = (a, b) => a+b

est équivalent à écrire:

exports.add = (a, b) => a+b

Donc ça va tant que vous n'attribuez pas une nouvelle valeur à la variable exports. Quand vous faites quelque chose comme ça:

exports = (a, b) => a+b 

lorsque vous attribuez une nouvelle valeur à exports, il n’a plus de référence à l’objet exporté et reste donc local dans votre module.

Si vous prévoyez d'assigner une nouvelle valeur à module.exports plutôt que d'ajouter de nouvelles propriétés à l'objet initial rendu disponible, vous devriez probablement envisager de procéder comme indiqué ci-dessous:

module.exports = exports = (a, b) => a+b

Le site Web de Node.js a une très bonne explication à ce sujet.

0

dans le noeud js le fichier module.js est utilisé pour exécuter le module.load temps system.every quand le noeud exécute un fichier, il enveloppera le contenu de votre fichier js comme suit

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

en raison de cette insertion dans le code source de js, vous pouvez accéder aux exportations, require, module, etc. Cette approche est utilisée car il n’existe aucun autre moyen d’écrire des fonctionnalités sur un fichier js.

puis le noeud exécute cette fonction encapsulée en utilisant c ++. à ce moment les objets exportés qui sont passés dans cette fonction seront remplis.

vous pouvez voir à l'intérieur de cette fonction paramètres exports et module. exports est en fait un membre public de la fonction constructeur du module.

regardez le code suivant

copier ce code dans 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();

copier ce code dans 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');}

maintenant exécuté en utilisant noeud

c'est la sortie

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

exports is [objet Objet]

object.keys de foo: name is function () {console.log ('fonction vers les exportations du module')} fonction vers les exportations du module

maintenant, supprimez la ligne commentée dans a.js et commentez la ligne au-dessus de cette ligne et supprimez la dernière ligne de b.js et exécutez.

dans javascript world, vous ne pouvez pas réaffecter un objet passé en paramètre, mais vous pouvez modifier le membre public de la fonction lorsque l'objet de cette fonction est défini en tant que paramètre pour une autre fonction

rappelez-vous

utilisez module.exports sur et uniquement si vous souhaitez obtenir une fonction lorsque vous utilisez require keyword. dans l'exemple ci-dessus, nous varfoo = require (a.js); vous pouvez voir que nous pouvons appeler foo en tant que fonction;

c'est ainsi que la documentation du noeud l'explique: "L'objet exports est créé par le système Module. Parfois, cela n'est pas acceptable, beaucoup souhaitent que leur module soit une instance d'une classe. Pour ce faire, affectez l'objet d'exportation souhaité à module.exports."

0
sidias