web-dev-qa-db-fra.com

Que signifient "module.exports" et "exports.methods" dans NodeJS / Express?

En regardant un aléatoire fichier source du cadre express pour NodeJS, il y a deux lignes de code que je ne comprends pas (ces lignes de code sont typiques de presque tous les fichiers NodeJS).

/**
 * Expose `Router` constructor.
 */

exports = module.exports = Router;

et

/**
 * Expose HTTP methods.
 */

var methods = exports.methods = require('./methods');

Je comprends que le premier morceau de code permet au reste des fonctions du fichier d'être exposées à l'application NodeJS , mais je ne comprends pas exactement comment cela fonctionne , ni ce que signifie le code de la ligne.

Que font exports et module.exports signifie vraiment?

Je crois que le 2ème morceau de code permet aux fonctions du fichier d'accéder à methods, mais encore une fois, comment fait-il exactement cela.

Fondamentalement, quels sont ces mots magiques: module et exports?

56
mrwooster

Pour être plus précis:

module est la variable de portée globale à l'intérieur d'un fichier.

Donc, si vous appelez require("foo") alors:

// foo.js
console.log(this === module); // true

Il agit de la même manière que window agit dans le navigateur.

Il y a aussi un autre objet global appelé global que vous pouvez écrire et lire dans n'importe quel fichier que vous voulez, mais qui implique la mutation de la portée globale et c'est [~ # ~] mal [~ # ~]

exports est une variable qui vit sur module.exports. C'est essentiellement ce que vous exportez lorsqu'un fichier est requis.

// foo.js
module.exports = 42;

// main.js
console.log(require("foo") === 42); // true

Il y a un problème mineur avec exports seul. Le contexte d'étendue _global + et module ne sont pas différents . (Dans le navigateur, le contexte de portée globale et window sont les mêmes).

// foo.js
var exports = {}; // creates a new local variable called exports, and conflicts with

// living on module.exports
exports = {}; // does the same as above
module.exports = {}; // just works because its the "correct" exports

// bar.js
exports.foo = 42; // this does not create a new exports variable so it just works

En savoir plus sur les exportations

79
Raynos

Pour développer la réponse de Raynos ...

exports est fondamentalement un alias pour module.exports - Je recommande simplement de ne pas l'utiliser. Vous pouvez exposer les méthodes et les propriétés d'un module en les définissant sur module.exports, comme suit:

//file 'module1.js'
module.exports.foo = function () { return 'bar' }
module.exports.baz = 5

Ensuite, vous y accédez dans votre code:

var module1 = require('module1')
console.log(module1.foo())
console.log(module1.baz)

Vous pouvez également remplacermodule.exports Entièrement pour fournir simplement un seul objet sur demande:

//glorp.js
module.exports = function () {
  this.foo = function () { return 'bar' }
  this.baz = 5
  return this // need to return `this` object here
}

Vous avez maintenant un joli prototype:

var g1 = new require('glorp')()
console.log(g1.foo())
console.log(g1.baz)

Il existe une myriade d'autres façons de jouer avec module.exports Et require. N'oubliez pas, require('foo')renvoie toujours la même instance même si vous l'appelez plusieurs fois.

Remarque

Pour que les éléments suivants fonctionnent,

var g1 = new require('glorp')()
console.log(g1.foo())
console.log(g1.baz) 

this doit être retourné dans la fonction affectée à module.exports. Sinon, vous obtiendrez un TypeError:

console.log(g1.foo())
          ^
TypeError: Cannot read property 'foo' of undefined
34
Tamzin Blake

Vous pouvez trouver la meilleure réponse dans le code source de node.js. Si quelqu'un a besoin de votre module js, votre script se transforme en fonction par nœud comme suit (voir src/node.js).

// require function does this..
(function (exports, require, module, __filename, __dirname) {
    ... your javascript contents...
});

Le nœud enveloppera votre script. Ensuite, le script ci-dessus sera exécuté comme suit:

//module.js
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);

Donc dans votre script,

exports is just module.exports.

Dans votre script, vous pouvez ajouter quelque chose à cet objet exports (fonctions ..). La fonction require retournera cet objet. Il s'agit du système de modules de node.js (spécification commonJS).

Mais attention à ne pas modifier module.exports. Sinon, vos exportations actuelles n'auront aucun sens.

15
jeremyko

module est un objet qui représente ce que ce fichier source particulier aimerait exposer publiquement. Au lieu d'avoir quelque chose qui ressemble aux fichiers d'en-tête dans le monde c/c ++, vous décrivez ce que le module exportations en définissant cet objet. le runtime du nœud utilise ensuite cet objet pour déterminer ce qui est "public" dans votre module.

c'est un concept similaire à l'exportation de fonctions à partir d'une DLL dans le monde compilé. vous devez définir explicitement les fonctions accessibles au monde extérieur. cela aide à l'encapsulation et vous permet d'organiser vos bibliothèques de manière propre.

1
Josh

Le code du module est enveloppé dans module.exports (Le module, peut-être composé par un autre module). Il existe de nombreuses façons de créer un module, mais celui-ci est très courant (et mon préféré).

// Dependencies
// const module = require('module');

// Module object
var foo = {}

// Internal property
foo._a = 'a';

// "Public" property
foo.b = 'b';

// Method
foo.fu = function() { return 'fu' };

// Export
module.exports = foo;