javascript - example - module.exports vs exports
¿Cuál es el propósito de Node.js module.exports y cómo lo usa? (11)
¿Cuál es el propósito de Node.js module.exports y cómo lo usa?
Parece que no puedo encontrar 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 al
module
actual. En particular,module.exports
es el mismo que el objeto de exportación. Veasrc/node.js
para más información.
Pero esto realmente no ayuda.
¿Qué hace exactamente module.exports
, y cuál sería un ejemplo simple?
¿Cuál es el propósito de un sistema de módulos?
Cumple las siguientes cosas:
- Mantiene nuestros archivos de la hinchazón a tamaños realmente grandes. Tener archivos con, por ejemplo, 5000 líneas de código en él es generalmente muy difícil de tratar durante el desarrollo.
- Hace cumplir la separación de preocupaciones. Tener nuestro código dividido en varios archivos nos permite tener nombres de archivo adecuados para cada archivo. De esta manera podemos identificar fácilmente qué hace cada módulo y dónde encontrarlo (asumiendo que hicimos una estructura de directorio lógica que sigue siendo su responsabilidad).
Tener módulos facilita la búsqueda de ciertas partes del código, lo que hace que nuestro código sea más fácil de mantener.
¿Como funciona?
NodejS
usa el sistema de módulos CommomJS que funciona de la siguiente manera:
- Si un archivo quiere exportar algo, debe declararlo mediante la sintaxis de
module.export
- Si un archivo quiere importar algo, tiene que declararlo usando la sintaxis de
require(''file'')
Ejemplo:
test1.js
const test2 = require(''./test2''); // returns the module.exports object of a file
test2.Func1(); // logs func1
test2.Func2(); // logs func2
test2.js
module.exports.Func1 = () => {console.log(''func1'')};
exports.Func2 = () => {console.log(''func2'')};
Otras cosas útiles para saber:
- Los módulos se están almacenando en caché . Cuando está cargando el mismo módulo en 2 archivos diferentes, el módulo solo debe cargarse una vez. La segunda vez que se llama a
require()
en el mismo módulo, se extrae de la memoria caché. - Los módulos se cargan en síncrono . Este comportamiento es obligatorio, si fuera asíncrono no podríamos acceder al objeto recuperado de
require()
inmediato.
Al dividir el código de su programa en varios archivos, module.exports
se utiliza para publicar variables y funciones para el consumidor de un módulo. La llamada require()
en su archivo de origen se reemplaza con el módulo correspondiente. module.exports
cargadas desde el módulo.
Recuerda al escribir módulos.
- Las cargas de los módulos se almacenan en caché, solo la llamada inicial evalúa JavaScript.
- Es posible usar variables y funciones locales dentro de un módulo, no todo tiene que ser exportado.
- El objeto
module.exports
también está disponible como forma abreviada deexports
. Pero al devolver una función única, siempre usemodule.exports
.
De acuerdo con: "Módulos Parte 2 - Escritura de módulos" .
Algunas cosas que debe tener cuidado si asigna una referencia a un nuevo objeto para exports
y / o modules.exports
:
1. Todas las propiedades / métodos previamente adjuntos a las exports
originales o module.exports
, por supuesto, se pierden porque el objeto exportado ahora hará referencia a otro nuevo.
Este es obvio, pero si agrega un método exportado al comienzo de un módulo existente, asegúrese de que el objeto exportado nativo 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 una de las exports
o module.exports
referencia a un nuevo valor, ya no harán 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 difícil. Si cambia la referencia a 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() {};
El enlace de referencia es así:
exports = module.exports = function(){
//....
}
Las propiedades de exports
o module.exports
, como funciones o variables, se expondrán fuera
Hay algo a lo que debe prestar más atención: no override
exportaciones.
por qué ?
debido a que exporta solo la referencia de module.exports, puede agregar las propiedades a las exportaciones, pero si invalida las exportaciones, el enlace de referencia se romperá.
buen ejemplo :
exports.name = ''william'';
exports.getName = function(){
console.log(this.name);
}
mal ejemplo :
exports = ''william'';
exports = function(){
//...
}
Si solo quieres exponer una sola función o variable, como esta:
// test.js
var name = ''william'';
module.exports = function(){
console.log(name);
}
// index.js
var test = require(''./test'');
test();
este módulo solo expone una función y la propiedad de nombre es privada para el exterior.
Esto ya ha sido respondido pero quería agregar algunas aclaraciones ...
Puede usar 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ás (por ejemplo, en el código de ejemplo de ExpressJS) es que configuras las propiedades en el objeto de exports
en un archivo .js que luego importas utilizando require()
Entonces, en un ejemplo de conteo simple, podrías tener:
(counter.js):
var count = 1;
exports.increment = function() {
count++;
};
exports.getCount = function() {
return count;
};
... luego en su aplicación (web.js, o en realidad 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 solo objeto, y puede agregar propiedades (cadenas, números, arreglos, funciones, cualquier cosa) al objeto que se devuelve al establecerlos en las exports
.
A veces querrá que el objeto devuelto de una llamada require()
sea una función a la que pueda llamar, en lugar de solo un objeto con propiedades. En ese caso, también necesita configurar module.exports
, como este:
(sayhello.js):
module.exports = exports = function() {
console.log("Hello World!");
};
(app.js):
var sayHello = require(''./sayhello.js'');
sayHello(); // "Hello World!"
La diferencia entre exportaciones y módulo.exportaciones se explica mejor en esta respuesta aquí .
Hay algunos módulos predeterminados o existentes en node.js cuando descarga e instala node.js como http, sys, etc.
Como ya están en node.js, cuando queremos usar estos módulos, básicamente nos gustan los módulos de importación , pero ¿por qué? Porque ya están presentes en el node.js. Importar es como tomarlos de node.js y ponerlos en tu programa. Y luego usarlos.
Si bien Exports es exactamente lo contrario, usted está creando el módulo que desea, digamos el módulo add.js y colocando ese módulo en el node.js, lo hace exportándolo.
Antes de escribir algo aquí, recuerde, module.exports.additionTwo es lo mismo que exports.additionTwo
Huh, así que esa es la razón, nos gusta
exports.additionTwo = function(x)
{return x+2;};
Ten cuidado con el camino
Digamos que usted ha creado un módulo add.js,
exports.additionTwo = function(x){
return x + 2;
};
Cuando ejecute esto en el símbolo del sistema NODE.JS:
node
var run = require(''addition.js'');
Esto hará un error diciendo
Error: no se puede encontrar el módulo add.js
Esto se debe a que el proceso node.js no puede agregar.js ya que no mencionamos la ruta. Por lo tanto, podemos establecer la ruta utilizando NODE_PATH
set NODE_PATH = path/to/your/additon.js
Ahora, esto debería ejecutarse exitosamente sin ningún error!
Una cosa más, también puede ejecutar el archivo add.js si no configura NODE_PATH, de vuelta a la línea de comandos de su nodejs:
node
var run = require(''./addition.js'');
Ya que estamos proporcionando la ruta aquí diciendo que está en el directorio actual ./
esto también debería ejecutarse con éxito.
La intención es:
La programación modular es una técnica de diseño de software que enfatiza la separación de la funcionalidad de un programa en módulos independientes e intercambiables, de manera que cada uno contiene todo lo necesario para ejecutar solo un aspecto de la funcionalidad deseada.
Imagino que se vuelve difícil escribir programas grandes sin código modular / reutilizable. En nodejs, podemos crear programas modulares que utilizan module.exports
definen lo que exponemos y module.exports
nuestro programa según nuestros require
.
Prueba este ejemplo:
fileLog.js
function log(string) { require(''fs'').appendFileSync(''log.txt'',string); }
module.exports = log;
stdoutLog.js
function log(string) { console.log(string); }
module.exports = log;
program.js
const log = require(''./stdoutLog.js'')
log(''hello world!'');
ejecutar
$ node program.js
¡Hola Mundo!
Ahora intente intercambiar ./stdoutLog.js por ./fileLog.js .
La propiedad module.exports o el objeto de exportación permiten que un módulo seleccione lo que se debe compartir con la aplicación.
Tengo un video en module_export disponible here
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 here .
A menos que su módulo utilice funciones o módulos específicos del nodo, le recomiendo que utilice las exports
lugar de module.exports
que no forma parte del estándar CommonJS y, en su mayoría, no es compatible con otras implementaciones.
Otra característica específica de NodeJS es cuando asigna una referencia a un nuevo objeto para exports
lugar de simplemente agregarle propiedades y métodos como en el último ejemplo proporcionado por Jed Watson en este hilo. Personalmente, desalentaría esta práctica, ya que esto rompe el soporte de referencia circular del mecanismo de módulos de CommonJS. Entonces, no es compatible con todas las implementaciones y el ejemplo de Jed se debe escribir de esta manera (o similar) para proporcionar un módulo más universal:
(sayhello.js):
exports.run = function() {
console.log("Hello World!");
}
(app.js):
var sayHello = require(''./sayhello'');
sayHello.run(); // "Hello World!"
O usando las características de ES6
(sayhello.js):
Object.assign(exports, {
// Put all your public API here
sayhello() {
console.log("Hello World!");
}
});
(app.js):
const { sayHello } = require(''./sayhello'');
sayHello(); // "Hello World!"
PS: Parece que Appcelerator también implementa módulos CommonJS, pero sin el soporte de referencia circular (ver: Módulos Appcelerator y CommonJS (almacenamiento en caché y referencias circulares) )
Un módulo encapsula código relacionado en una sola unidad de código. Al crear un módulo, esto puede interpretarse como mover todas las funciones relacionadas a un archivo.
Supongamos que hay un archivo Hello.js que incluye dos funciones
sayHelloInEnglish = function() {
return "Hello";
};
sayHelloInSpanish = function() {
return "Hola";
};
Escribimos una función solo cuando la utilidad del código es más de una llamada.
Supongamos que queremos aumentar la utilidad de la función a un archivo diferente, por ejemplo World.js, en este caso, exportar un archivo aparece en la imagen, que puede obtenerse mediante module.exports.
Puede exportar la función mediante el código que se indica a continuación.
var anyVariable={
sayHelloInEnglish = function() {
return "Hello";
};
sayHelloInSpanish = function() {
return "Hola";
};
}
module.export=anyVariable;
Ahora solo necesita solicitar el nombre del archivo en World.js para usar esas funciones
var world= require("./hello.js");
module.exports
es el objeto que realmente se devuelve como resultado de una llamada require
.
La variable de exports
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ía algo como esto:
var myFunc1 = function() { ... };
var 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 utilizarías:
var m = require(''./mymodule'');
m.myFunc1();
donde la última línea muestra cómo el resultado de require
es (generalmente) solo un objeto plano a cuyas propiedades se puede acceder.
NB: si sobrescribe las exports
, dejará de referirse a module.exports
. Por lo tanto, si desea asignar un nuevo objeto (o una referencia de función) a las exports
, también debe asignar ese nuevo objeto a module.exports
Vale la pena señalar que el nombre agregado al objeto de exports
no tiene que ser el mismo que el nombre de ámbito interno del módulo para el valor que está agregando, por lo que podría tener:
var myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required
seguido por:
var m = require(''./mymodule'');
m.shortName(); // invokes module.myVeryLongInternalName