web-dev-qa-db-fra.com

Différence entre "module.exports" et "exports" dans le système de modules CommonJs

Sur cette page ( http://docs.nodejitsu.com/articles/getting-started/what-is-require ), il est indiqué que "Si vous souhaitez définir l'objet d'exportations comme une fonction ou un nouvel objet, vous devez utiliser l'objet module.exports. "

Ma question est pourquoi.

// right
module.exports = function () {
  console.log("hello world")
}
// wrong
exports = function () {
  console.log("hello world")
}

J'ai console.logged le résultat (result=require(example.js)) et le premier est [Function] le deuxième est {}.

Pourriez-vous s'il vous plaît expliquer la raison derrière cela? J'ai lu le post ici: module.exports vs exports dans Node.js . C'est utile, mais n'explique pas pourquoi il est conçu de cette façon. Y aura-t-il un problème si la référence des exportations est renvoyée directement?

243

module est un objet JavaScript simple avec une propriété exports. exports est une variable JavaScript simple dont la valeur est définie sur module.exports. À la fin de votre fichier, node.js 'retournera' module.exports à la fonction require. Voici un moyen simplifié d’afficher un fichier JS dans Node:

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

// your code

return module.exports;

Si vous définissez une propriété sur exports, comme exports.a = 9;, cela définira également module.exports.a, car les objets sont transmis en tant que références en JavaScript, ce qui signifie que si vous définissez plusieurs variables de la même manière objet, ils sont tous le même objet; alors exports et module.exports sont le même objet.
Mais si vous définissez exports sur quelque chose de nouveau, il ne sera plus réglé sur module.exports, de sorte que exports et module.exports ne sont plus le même objet.

555
goto-bus-stop

La réponse de Renée est bien expliquée. Ajout à la réponse avec un exemple:

Node fait beaucoup de choses dans votre fichier et l'un des plus importants est le WRAPPING de votre fichier. Le code source de nodejs "module.exports" est renvoyé. Permet de prendre du recul et de comprendre le wrapper. Supposons que vous ayez

saluer.js

var greet = function () {
   console.log('Hello World');
};

module.exports = greet;

le code ci-dessus est encapsulé sous la forme IIFE (Expression de fonction immédiatement appelée) dans le code source de nodejs, comme suit:

(function (exports, require, module, __filename, __dirname) { //add by node

      var greet = function () {
         console.log('Hello World');
      };

      module.exports = greet;

}).apply();                                                  //add by node

return module.exports;                                      //add by node

et la fonction ci-dessus est appelée (.apply ()) et renvoyée module.exports. À ce stade, module.exports et exportations pointant vers la même référence.

Maintenant, imaginez que vous ré-écriviez greet.js en tant que

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

la sortie sera

[Function]
{}

la raison en est: module.exports est un objet vide. Nous n'avons pas défini quoi que ce soit sur module.exports. Nous avons plutôt défini exports = function () ..... dans le nouveau message greet.js. Ainsi, module.exports est vide.

Techniquement, les exportations et module.exports doivent pointer vers la même référence (c'est correct !!). Mais nous utilisons "=" lors de l'affectation de function () .... aux exportations, ce qui crée un autre objet dans la mémoire. Ainsi, module.exports et exports produisent des résultats différents. En ce qui concerne les exportations, nous ne pouvons pas le remplacer.

Maintenant, imaginez que vous réécriviez (ceci s'appelle Mutation) greet.js (faisant référence à Renee) comme

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

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

la sortie sera

{ a: [Function] }
{ a: [Function] }

Comme vous pouvez le voir, module.exports et les exportations pointent vers la même référence qui est une fonction. Si vous définissez une propriété sur les exportations, elle le sera sur module.exports car, dans JS, les objets sont passés par référence.

La conclusion est toujours d'utiliser module.exports pour éviter toute confusion. J'espère que cela t'aides. Bonne codage :)

40
Sdembla

En outre, une chose qui peut aider à comprendre:

math.js

this.add = function (a, b) {
    return a + b;
};

client.js

var math = require('./math');
console.log(math.add(2,2); // 4;

Super, dans ce cas:

console.log(this === module.exports); // true
console.log(this === exports); // true
console.log(module.exports === exports); // true

Ainsi, par défaut, "this" est égal à module.exports.

Toutefois, si vous modifiez votre implémentation pour:

math.js

var add = function (a, b) {
    return a + b;
};

module.exports = {
    add: add
};

Dans ce cas, cela fonctionnera bien, cependant, "ceci" n'est plus égal à module.exports, car un nouvel objet a été créé.

console.log(this === module.exports); // false
console.log(this === exports); // true
console.log(module.exports === exports); // false

Et maintenant, ce qui sera retourné par l'exigence, c'est ce qui a été défini dans le module.exports, pas celui-ci ou les exportations, plus.

Une autre façon de le faire serait:

math.js

module.exports.add = function (a, b) {
    return a + b;
};

Ou:

math.js

exports.add = function (a, b) {
    return a + b;
};
19
Rodrigo Branas

La réponse de René sur la relation entre exports et module.exports est assez claire, il s'agit de références javascript. Je veux juste ajouter que:

Nous voyons cela dans de nombreux modules de nœuds:

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

Cela garantira que même si nous modifiions module.exports, nous pouvons toujours utiliser les exportations en faisant en sorte que ces deux variables pointent vers le même objet.

13
fengshuo