¿Cuál es el propósito de Node.js module.exports y cómo se usa?
¿Cuál es el propósito de Node.js module.exports
y cómo se usa?
Parece que no puedo encontrar ninguna información sobre esto, pero parece ser una parte bastante importante de Node.js, como lo veo a menudo en el código fuente.
Según la documentación de Node.js :
módulo
Una referencia a la actualidad
module
. En particularmodule.exports
es el mismo que el objeto de exportación. Consultesrc/node.js
para obtener más información.
Pero esto realmente no ayuda.
¿Qué hace exactamente module.exports
y cuál sería un ejemplo sencillo?
module.exports
es el objeto que realmente se devuelve como resultado de una require
llamada.
La exports
variable se establece inicialmente en ese mismo objeto (es decir, es un "alias" abreviado), por lo que en el código del módulo normalmente escribirías algo como esto:
let myFunc1 = function() { ... };
let myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;
para exportar (o "exponer") las funciones de ámbito interno myFunc1
y myFunc2
.
Y en el código de llamada usarías:
const m = require('./mymodule');
m.myFunc1();
donde la última línea muestra cómo el resultado de require
es (generalmente) solo un objeto simple a cuyas propiedades se puede acceder.
NB: si sobrescribe, exports
ya no hará referencia a module.exports
. Entonces, si desea asignar un nuevo objeto (o una referencia de función), exports
también debe asignar ese nuevo objeto amodule.exports
Vale la pena señalar que el nombre agregado al exports
objeto no tiene que ser el mismo que el nombre de ámbito interno del módulo para el valor que estás agregando, por lo que podrías tener:
let myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required
seguido por:
const m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName
Esto ya ha sido respondido pero quería agregar una aclaración...
Puede usar ambos exports
y module.exports
para importar código a su aplicación de esta manera:
var mycode = require('./path/to/mycode');
El caso de uso básico que verá (por ejemplo, en el código de ejemplo de ExpressJS) es que establece propiedades en el exports
objeto en un archivo .js que luego importa usandorequire()
Entonces, en un ejemplo simple de conteo, podría tener:
(contador.js):
var count = 1;
exports.increment = function() {
count++;
};
exports.getCount = function() {
return count;
};
... luego en su aplicación (web.js, o realmente cualquier otro archivo .js):
var counting = require('./counter.js');
console.log(counting.getCount()); // 1
counting.increment();
console.log(counting.getCount()); // 2
En términos simples, puede pensar en los archivos requeridos como funciones que devuelven un único objeto, y puede agregar propiedades (cadenas, números, matrices, funciones, cualquier cosa) al objeto devuelto configurándolos en exports
.
A veces querrás que el objeto devuelto por una require()
llamada sea una función que puedas llamar, en lugar de simplemente un objeto con propiedades. En ese caso también necesitas configurarlo module.exports
, así:
(saluda.js):
module.exports = exports = function() {
console.log("Hello World!");
};
(aplicación.js):
var sayHello = require('./sayhello.js');
sayHello(); // "Hello World!"
La diferencia entre exportaciones y module.exports se explica mejor en esta respuesta aquí .
Tenga en cuenta que el mecanismo del módulo NodeJS se basa en módulos CommonJS que son compatibles con muchas otras implementaciones como RequireJS , pero también SproutCore , CouchDB , Wakanda , OrientDB , ArangoDB , RingoJS , TeaJS , SilkJS , curl.js o incluso Adobe Photoshop (a través de PSLib) . ). Puede encontrar la lista completa de implementaciones conocidas aquí .
A menos que su módulo utilice funciones o módulos específicos del nodo, le recomiendo encarecidamente que los utilice exports
en lugar de module.exports
los cuales no forman parte del estándar CommonJS y, en su mayoría, no son compatibles con otras implementaciones.
Otra característica específica de NodeJS es cuando asigna una referencia a un nuevo objeto exports
en lugar de simplemente agregarle propiedades y métodos como en el último ejemplo proporcionado por Jed Watson en este hilo. Personalmente desaconsejaría esta práctica ya que rompe el soporte de referencia circular del mecanismo de módulos CommonJS. Entonces no es compatible con todas las implementaciones y el ejemplo de Jed debería escribirse de esta manera (o una similar) para proporcionar un módulo más universal:
(saluda.js):
exports.run = function() {
console.log("Hello World!");
}
(aplicación.js):
var sayHello = require('./sayhello');
sayHello.run(); // "Hello World!"
O usando las funciones de ES6
(saluda.js):
Object.assign(exports, {
// Put all your public API here
sayhello() {
console.log("Hello World!");
}
});
(aplicación.js):
const { sayHello } = require('./sayhello');
sayHello(); // "Hello World!"
PD: Parece que Appcelerator también implementa módulos CommonJS, pero sin el soporte de referencia circular (consulte: Módulos Appcelerator y CommonJS (almacenamiento en caché y referencias circulares) )
Algunas cosas que debes tener en cuenta si asignas una referencia a un nuevo objeto a exports
y/o modules.exports
:
1. Todas las propiedades/métodos previamente adjuntos al original exports
o, module.exports
por supuesto, se pierden porque el objeto exportado ahora hará referencia a otro nuevo.
Esto es obvio, pero si agrega un método exportado al comienzo de un módulo existente, asegúrese de que el objeto nativo exportado no haga referencia a otro objeto al final.
exports.method1 = function () {}; // exposed to the original exported object
exports.method2 = function () {}; // exposed to the original exported object
module.exports.method3 = function () {}; // exposed with method1 & method2
var otherAPI = {
// some properties and/or methods
}
exports = otherAPI; // replace the original API (works also with module.exports)
2. En caso de que uno de exports
ellos module.exports
haga referencia a un nuevo valor, ya no hace referencia al mismo objeto.
exports = function AConstructor() {}; // override the original exported object
exports.method2 = function () {}; // exposed to the new exported object
// method added to the original exports object which not exposed any more
module.exports.method3 = function () {};
3. Consecuencia complicada. Si cambia la referencia a ambos exports
y module.exports
, es difícil decir qué API está expuesta (parece que module.exports
gana)
// override the original exported object
module.exports = function AConstructor() {};
// try to override the original exported object
// but module.exports will be exposed instead
exports = function AnotherConstructor() {};
la propiedad module.exports o el objeto exports permite que un módulo seleccione lo que se debe compartir con la aplicación
Tengo un vídeo sobre module_export disponible aquí