module.exports vs exportaciones en Node.js

Resuelto Andreas Köberle asked hace 13 años • 24 respuestas

Encontré el siguiente contrato en un módulo de Node.js:

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

Me pregunto cuál es la diferencia entre module.exportsy exportspor qué se usan ambos aquí.

Andreas Köberle avatar Aug 21 '11 16:08 Andreas Köberle
Aceptado

Aunque la pregunta fue respondida y aceptada hace mucho tiempo, solo quiero compartir mis 2 centavos.

Puedes imaginar que al principio de tu archivo hay algo como (solo como explicación):

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

ingrese la descripción de la imagen aquí

Entonces, hagas lo que hagas, ten en cuenta que module.exportsy NO exportsse devolverá de tu módulo cuando requieras ese módulo desde otro lugar.

Entonces, cuando haces algo como:

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

Está agregando 2 funciones ay bal objeto al que module.exportsapunta, por lo que el typeofresultado devuelto será object:{ a: [Function], b: [Function] }

Por supuesto, este es el mismo resultado que obtendrá si utiliza module.exportsen este ejemplo en lugar de exports.

Este es el caso en el que desea module.exportsque se comporte como un contenedor de valores exportados. Mientras que, si solo desea exportar una función constructora, entonces hay algo que debe saber sobre el uso module.exportsde o exports. Recuerde que module.exportsse le devolverá cuando requiera algo, no exports.

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

Ahora typeofel resultado devuelto es 'function'y puede solicitarlo e invocarlo inmediatamente como:
var x = require('./file1.js')();porque sobrescribe el resultado devuelto para que sea una función.

Sin embargo, al usar exportsno puedes usar algo como:

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

Porque con exports, la referencia ya no apunta al objeto al que module.exportsapunta, por lo que ya no hay relación entre exportsy module.exports. En este caso module.exportstodavía apunta al objeto vacío {}que será devuelto.

La respuesta aceptada de otro tema también debería ayudar: ¿ JavaScript pasa por referencia?

Srle avatar Oct 19 '2014 15:10 Srle

La configuración module.exportspermite database_modulellamar a la función como una función cuando required. La simple configuración exportsno permitiría exportar la función porque el nodo exporta las module.exportsreferencias del objeto. El siguiente código no permitiría al usuario llamar a la función.

módulo.js

Lo siguiente no funcionará.

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

Lo siguiente funcionará si module.exportsestá configurado.

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

consola

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

Básicamente, node.js no exporta el objeto al que exportshace referencia actualmente, sino que exporta las propiedades de lo que exportshace referencia originalmente. Aunque Node.js exporta las module.exportsreferencias de objetos, lo que le permite llamarlo como una función.


2da razón menos importante

Configuran ambos module.exportsy exportspara asegurarse de que exportsno haga referencia al objeto exportado anterior. Al configurar ambos, los utiliza exportscomo taquigrafía y evita posibles errores más adelante.

Usar exports.prop = true en lugar de module.exports.prop = trueguarda caracteres y evita confusiones.

Lime avatar Aug 22 '2011 03:08 Lime

Básicamente la respuesta está en lo que realmente sucede cuando se requiere un módulo mediante requireuna declaración. Suponiendo que esta es la primera vez que se requiere el módulo.

Por ejemplo:

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

Contenido del archivo 1.js:

module.exports = '123';

Cuando se ejecuta la declaración anterior, Modulese crea un objeto. Su función constructora es:

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 puede ver, cada objeto de módulo tiene una propiedad con nombre exports. Esto es lo que finalmente se devuelve como parte de require.

El siguiente paso de require es empaquetar el contenido de file1.js en una función anónima como se muestra a continuación:

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

Y esta función anónima se invoca de la siguiente manera, moduleaquí se refiere al ModuleObjeto creado 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 de la función, exportsel argumento formal se refiere a module.exports. En esencia, es una comodidad proporcionada al programador del módulo.

Sin embargo, esta comodidad debe ejercerse con cuidado. En cualquier caso, si intentamos asignar un nuevo objeto a las exportaciones, asegúrese de hacerlo de esta manera.

exports = module.exports = {};

Si lo hacemos de forma incorrecta , module.exportsseguirá apuntando al objeto creado como parte de la instancia del módulo.

exports = {};

Como resultado, agregar algo al objeto de exportación anterior no tendrá ningún efecto en el objeto module.exports y no se exportará ni devolverá nada como parte del requisito.

Chandu avatar Jul 30 '2013 10:07 Chandu

Inicialmente, module.exports=exportsy la requirefunción devuelve el objeto module.exportsal que se refiere.

si agregamos propiedad al objeto, digamos exports.a=1, entonces module.exports y exports aún se refieren al mismo objeto. Entonces, si llamamos a require y asignamos el módulo a una variable, entonces la variable tiene una propiedad a y su valor es 1;

Pero si anulamos uno de ellos, por ejemplo, exports=function(){}, ahora son diferentes : exports se refiere a un nuevo objeto y module.exports se refiere al objeto original. Y si requerimos el archivo, no devolverá el nuevo objeto, ya que module.exports no se refiere al nuevo objeto.

Para mí, seguiré agregando nuevas propiedades o anularé ambas a un nuevo objeto. Simplemente anular uno no está bien. Y tenga en cuenta que ese module.exportses el verdadero jefe.

cameron avatar Aug 12 '2013 02:08 cameron

exportsy module.exportsson los mismos a menos que los reasigne exportsdentro de su módulo.

La forma más sencilla de pensarlo es pensar que esta línea está implícitamente en la parte superior de cada módulo.

var exports = module.exports = {};

Si, dentro de tu módulo, reasignas exports, entonces lo reasignas dentro de tu módulo y ya no es igual a module.exports. Es por esto que, si deseas exportar una función, debes hacer:

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

Si simplemente asignara su function() { ... }a exports, lo reasignaría exportspara ya no señalar module.exports.

Si no desea hacer referencia a su función cada module.exportsvez, puede hacer:

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

Observe que module.exportses el argumento más a la izquierda.

Adjuntar propiedades exportsno es lo mismo ya que no lo está reasignando. Por eso esto funciona

exports.foo = function() { ... }
dustin.schultz avatar Sep 25 '2015 15:09 dustin.schultz