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.
La définition de module.exports
permet à la fonction database_module
d'être appelée comme une fonction lorsque required
name__. Définir simplement exports
ne 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.
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 exports
référence actuellement, mais exporte les propriétés de ce que exports
fait 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.
Ils définissent à la fois module.exports
et exports
pour s'assurer que exports
ne fait pas référence à l'objet exporté antérieur. En définissant les deux, vous utilisez le nom exports
et é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.
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;
Ainsi, quoi que vous fassiez, gardez simplement à l'esprit que module.exports
et NOT exports
seront 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 typeof
le résultat renvoyé sera un object
name__: { a: [Function], b: [Function] }
Bien entendu, vous obtiendrez le même résultat si vous utilisez module.exports
dans cet exemple au lieu de exports
name__.
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 exports
name __; (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 exports
name__, 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 exports
name__, la référence ne "pointe" plus sur l'objet où module.exports
est pointé, il n'y a donc plus de relation entre exports
et 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?
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.
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.
exports
et module.exports
sont identiques, sauf si vous réaffectez exports
dans 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 exports
name__, 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() { ... }
à exports
name__, vous réaffecteriez exports
pour 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 à exports
n'est pas la même, car vous ne la réaffectez pas. C'est pourquoi cela fonctionne
exports.foo = function() { ... }
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}
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:
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.
exports.abc = function(){}; // works!
exports.efg = function(){}; // works!
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)
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;
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
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);
É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.
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); //{}
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
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);
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.
"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
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.exports -> utiliser comme utilitaire singleton
2. module-exports -> utiliser comme objets logiques tels que service, modèle, etc.
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'
module.exports
etexports
pointent vers le mêmefunction 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 b
sur la ligne 3 par a
name__, la sortie est inversée. La conclusion est:
a
etb
sont indépendants.
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 exports
au lieu de module.exports
.
Vous serez donc heureux si exports
et 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.
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
module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true
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
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."