Módulos
Node.js trata cada archivo JavaScript como un módulo independiente.Por ejemplo, si tiene un archivo que contiene algún código y este archivo tiene un nombre xyz.js
, este archivo se trata como un módulo en Node y puede decir que ha creado un módulo llamado xyz
.

Tomemos un ejemplo para entender esto mejor.
Tiene un archivo llamado circle.js
que consiste en la lógica para calcular el área y la circunferencia de un círculo de un radio determinado, como se indica a continuación:
circle.js
Puede llamar al circle.js
archivo un módulo llamado circle
.
Quizás se pregunte por qué es necesario tener varios módulos. Podría haber escrito todo el código en un solo módulo. Bueno, es muy importante escribir código modular. Por modular, quiero decir que su código debe ser independiente y debe estar débilmente acoplado. Imagina que hay una aplicación grande y tienes todo tu código escrito en un solo lugar, solo un archivo. Demasiado desordenado, ¿verdad?
¿Cómo se ejecuta el código escrito dentro de un módulo?
Antes de ejecutar el código escrito dentro de un módulo, Node toma todo el código y lo encierra en un contenedor de funciones. La sintaxis de este contenedor de funciones es:

El contenedor de funciones para el circle
módulo se verá como el que se muestra a continuación:
Puede ver que hay un contenedor de funciones en el nivel raíz que abarca todo el código escrito dentro del circle
módulo.
Esta es la ventaja más significativa de tener módulos en Node.js. Incluso si define una variable global en un módulo usando var
, let
o const
palabras clave, las variables tienen un alcance local para el módulo en lugar de un alcance global. Esto sucede porque cada módulo tiene un envoltorio de función propio y el código escrito dentro de una función es local a esa función y no se puede acceder fuera de esta función.

Imaginemos que hay dos módulos - A y B . El código escrito en el interior del módulo A está encerrado dentro de la función de contenedor que corresponde al módulo A . Algo similar ocurre con el código escrito dentro del módulo B . Debido a que el código perteneciente a ambos módulos está incluido dentro de diferentes funciones, estas funciones no podrán acceder al código de la otra. (¿Recuerda que cada función en JavaScript tiene su propio alcance local?) Esta es la razón por la que el módulo A no puede acceder al código escrito dentro del módulo B y viceversa.
Los cinco parámetros - exports
, require
, module
, __filename
, __dirname
están disponibles dentro de cada módulo en el Nodo. Aunque estos parámetros son globales para el código dentro de un módulo, son locales para el módulo (debido al envoltorio de funciones como se explicó anteriormente). Estos parámetros proporcionan información valiosa relacionada con un módulo.
Repasemos el circle
módulo, que viste antes. Hay tres construcciones definidas en este módulo: una variable constante PI
, una función nombrada calculateArea
y otra función nombrada calculateCircumference
. Un punto importante a tener en cuenta es que todas estas construcciones son privadas para el circle
módulo de forma predeterminada. Significa que no puede usar estas construcciones en ningún otro módulo a menos que se especifique explícitamente.
Entonces, la pregunta que surge ahora es ¿cómo se especifica algo en un módulo que pueda ser utilizado por algún otro módulo? Aquí es cuando los parámetros module
& require
del contenedor de funciones son útiles. Analicemos estos dos parámetros en este artículo.
module
El module
parámetro (más bien una palabra clave en un módulo en Node) se refiere al objeto que representa el módulo actual . exports
es una clave del module
objeto, cuyo valor correspondiente es un objeto. El valor predeterminado de module.exports
objeto es {}
(objeto vacío). Puede verificar esto registrando el valor de la module
palabra clave dentro de cualquier módulo. Comprobemos cuál es el valor del module
parámetro dentro del circle
módulo.
circle.js
Tenga en cuenta que hay una console.log(module);
declaración al final del código en el archivo anterior. Cuando vea la salida, registrará el module
objeto, que tiene una clave nombrada exports
y el valor correspondiente a esta clave es {}
(un objeto vacío).
Ahora, ¿qué hace el module.exports
objeto? Bueno, se usa para definir cosas que un módulo puede exportar. Todo lo que se exporta desde un módulo puede, a su vez, estar disponible para otros módulos. Exportar algo es bastante sencillo. Solo necesita agregarlo al module.exports
objeto. Hay tres formas de agregar algo al module.exports
objeto que se va a exportar. Analicemos estos métodos uno por uno.
Método 1:
(Definir construcciones y luego usar múltiples module.exports
declaraciones para agregar propiedades)
En el primer método, primero define las construcciones y luego usa múltiples declaraciones module.exports donde cada declaración se usa para exportar algo de un módulo. Veamos este método en acción y veamos cómo puede exportar las dos funciones definidas en el circle
módulo.
circle.js
Como les dije antes, module
es un objeto que tiene la clave nombrada exports
y esta clave ( module.exports
), a su vez, consiste en otro objeto. Ahora, si observa el código proporcionado anteriormente, todo lo que está haciendo es agregar nuevas propiedades (pares clave-valor) al module.exports
objeto.
La primera propiedad tiene la clave calculateArea
(definido en la línea 19)y el valor escrito en el lado derecho del operador de asignación es la función definida con el nombre calculateArea
(en la línea 9).
La segunda propiedad (definida en la línea 20) tiene la clave calculateCircumference
y el valor es la función definida con el nombre calculateCircumference
(en la línea 16).
Por lo tanto, ha asignado dos propiedades (pares clave-valor) al module.exports
objeto.
Además, no olvidemos que ha utilizado la notación de puntos aquí. Alternativamente, puede usar la notación entre corchetes para asignar las propiedades al module.exports
objeto y agregar las funciones, calculateArea
y calculateCircumference
especificando las teclas que siguen a la notación entre corchetes. Por lo tanto, puede escribir las siguientes dos líneas para agregar propiedades al module.exports
objeto usando notación entre corchetes mientras reemplaza las dos últimas líneas (usando notación de puntos) en el código dado arriba:
// exporting stuff by adding to module.exports object using the bracket notation
module.exports['calculateArea'] = calculateArea;module.exports['calculateCircumference'] = calculateCircumference;
Intentemos ahora registrar el valor del module.exports
objeto después de agregar las propiedades. Tenga en cuenta que la siguiente declaración se agrega al final del código en el archivo que se muestra a continuación:
// logging the contents of module.exports object after adding properties to it
console.log(module.exports);
circle.js
Revisemos el resultado de este código y veamos si todo funciona bien. Para hacer esto, guarde su código y ejecute el siguiente comando en su Terminal :
node circle
Salida:
{ calculateArea: [Function: calculateArea], calculateCircumference: [Function: calculateCircumference] }
Se registran las construcciones calculateArea
y calculateCircumference
, agregadas al module.exports
, objeto. Por lo tanto, agregó con éxito las dos propiedades en el module.exports
objeto para que las funciones calculateArea
y calculateCircumference
puedan exportarse desde el circle
módulo a algún otro módulo.
En este método, primero definió todas las construcciones y luego usó múltiples declaraciones module.exports donde cada declaración se usa para agregar una propiedad al module.exports
objeto.
Método 2:
(Definir construcciones y luego usar una sola module.exports
declaración para agregar propiedades)
Otra forma es definir todas las construcciones primero (como lo hizo en el método anterior) pero use una sola module.exports
declaración para exportarlas todas. Este método es similar a la sintaxis de la notación literal de objeto en la que agrega todas las propiedades a un objeto a la vez.
Aquí, usó la notación literal del objeto y agregó ambas funciones, calculateArea
y calculateCircumference
(todas a la vez) al module.exports
objeto escribiendo una sola declaración module.exports .
Si verifica la salida de este código, obtendrá el mismo resultado que obtuvo anteriormente al usar el método 1.
Método 3:
(Agregar propiedades al module.exports
objeto mientras se definen construcciones)
En este método, puede agregar las construcciones al module.exports
objeto mientras las define. Veamos cómo se puede adoptar este método en nuestro circle
módulo.
En el código dado arriba, puede ver que las funciones en el módulo se agregan al module.exports
objeto cuando se definen. Veamos cómo funciona esto. Está agregando una clave calculateArea
al module.exports
objeto y el valor correspondiente a esta clave es la definición de función.
Tenga en cuenta que la función ya no tiene ningún nombre y es una función anónima que solo se trata como un valor para una clave de un objeto. Por lo tanto, no se puede hacer referencia a esta función en el circle
módulo y no se puede invocar esta función dentro de este módulo escribiendo la siguiente declaración:
calculateArea(8);
Si intenta ejecutar la declaración anterior, obtendrá una ReferenceError
declaración calculateArea is not defined
.
Ahora que ha aprendido cómo puede especificar qué se debe exportar de un módulo, ¿cómo cree que el otro módulo podrá utilizar el material exportado? Debe importar el módulo a algún otro módulo para poder utilizar el material exportado del primero en el segundo. Aquí es cuando necesitamos discutir otro parámetro llamado require
.
exigir
require
palabra clave se refiere a una función que se usa para importar todas las construcciones exportadas usando el module.exports
objeto de otro módulo. Si tiene un módulo x en el que está exportando algunas construcciones usando el module.exports
objeto y desea importar estas construcciones exportadas en el módulo y , entonces necesita requerir el módulo x en el módulo y usando la require
función. El valor devuelto por la require
función en el módulo y es igual al module.exports
objeto en el módulo x .

Entendamos esto usando el ejemplo que discutimos anteriormente. Ya tiene el circle
módulo desde el que está exportando las funciones calculateArea
y calculateCircumference
. Ahora, veamos cómo puede usar la require
función para importar el material exportado en otro módulo.
Primero creemos un nuevo archivo en el que utilizará el código exportado del circle
módulo. Vamos a nombrar este archivo app.js
y puede llamarlo app
módulo.
El objetivo es importar al app
módulo todo el código exportado desde el circle
módulo. Entonces, ¿cómo puede incluir su código escrito en un módulo dentro de otro módulo?
Considere la sintaxis de la require
función dada a continuación:
const variableToHoldExportedStuff = require('idOrPathOfModule');
La require
función toma un argumento que puede ser un ID o una ruta. La identificación se refiere a la identificación (o nombre) del módulo necesario. Debe proporcionar la ID como argumento cuando utilice los módulos de terceros o los módulos principales proporcionados por Node Package Manager. Por otro lado, cuando tiene módulos personalizados definidos por usted, debe proporcionar la ruta del módulo como argumento. Puede leer más sobre la función require en este enlace.
Debido a que ya ha definido un módulo personalizado con nombre circle
, proporcionará la ruta como argumento para la require
función.
app.js
Si lo nota claramente, el punto al comienzo de la ruta significa que es una ruta relativa y que los módulos app
y circle
están almacenados en la misma ruta.
Iniciemos sesión en la consola con la circle
variable, que contiene el resultado devuelto por la require
función. Veamos qué contiene esta variable.
app.js
Verifique el resultado guardando todo su código y ejecutando el siguiente comando en su Terminal (este último no es necesario si tiene el nodemon
paquete instalado):
node app
Salida:
{ calculateArea: [Function: calculateArea],calculateCircumference: [Function: calculateCircumference] }
Como puede ver, la require
función devuelve un objeto, cuyas claves son los nombres de las variables / funciones que se han exportado desde el módulo requerido ( circle
). En resumen, la require
función devuelve el module.exports
objeto.
Accedamos ahora a las funciones importadas del circle
módulo.
app.js
Salida:
Area = 200.96, Circumference = 50.24
¿Qué crees que pasará si intento acceder a la variable nombrada PI
definida en el circle
módulo dentro del app
módulo?
app.js
Salida:
Area = 200.96, Circumference = 50.24pi = undefined
¿Puedes averiguar por qué pi
es undefined
? Bueno, esto se debe a que la variable PI
no se exporta desde el circle
módulo. ¿Recuerda el punto en el que le dije que no puede acceder al código escrito dentro de un módulo en otro módulo porque todo el código escrito dentro de un módulo es privado a menos que se exporte? Aquí, está intentando acceder a algo que no se ha exportado desde el circle
módulo y es privado para él.
Por lo tanto, es posible que se pregunte por qué no obtuvo un ReferenceError
. Esto se debe a que está intentando acceder a una clave nombrada PI
dentro del module.exports
objeto devuelto por la require
función. También sabe que la clave nombrada PI
no existe en el module.exports
objeto.
Tenga en cuenta que cuando intenta acceder a una clave que no existe en un objeto, obtiene el resultado como undefined
. Esta es la razón por la que obtiene PI
como en undefined
lugar de obtener un ReferenceError
.
Ahora, exportemos la variable PI
del circle
módulo y veamos si cambia la respuesta.
circle.js
Observe que aquí no está utilizando el nombre de la variable PI
como clave de la propiedad agregada al module.exports
objeto. En cambio, estás usando otro nombre, que es lifeOfPi
.
Esto es algo interesante de notar. Cuando está exportando alguna construcción de codificación, puede dar cualquier nombre a la clave al agregar una propiedad agregada al module.exports
objeto. No es obligatorio utilizar el mismo nombre que utilizó al definir la construcción. Esto se debe a que puede utilizar cualquier identificador válido como clave en un objeto JavaScript. Por lo tanto, en el lado izquierdo del operador de asignación, puede usar cualquier identificador válido, pero en el lado derecho del operador de asignación, debe proporcionar un valor que se define como una construcción en el alcance del módulo actual (como usted he definido las variables y funciones en el módulo 'círculo').
Un punto importante a tener en cuenta es que al importar algo de otro módulo en el módulo actual, debe utilizar la misma clave que utilizó al exportarlo.
app.js
Debido a que usó la clave lifeOfPi
, debe usar la misma clave para acceder a la variable PI
definida en el circle
módulo, como se hace en el código dado arriba.
Salida:
Area = 200.96, Circumference = 50.24pi = 3.14
¿Qué crees que pasará si usas el nombre de la variable en lugar de usar la clave que se usó durante la exportación? En resumen, intentemos acceder a PI
(nombre de la variable) en lugar de lifeOfPi
(clave utilizada durante la exportación PI
).
app.js
Salida:
Area = 200.96, Circumference = 50.24pi = undefined
Esto sucede porque el module.exports
objeto ya no conoce la variable PI
. Solo conoce las claves que se le agregaron. Debido a que la clave utilizada para exportar la variable PI
es lifeOfPi
, la última solo se puede usar para acceder a la primera.
TL; DR
- Cada archivo de Node.js se denomina módulo .
- Antes de ejecutar el código escrito en un módulo, Node.js toma todo el código escrito dentro del módulo y lo convierte en un contenedor de funciones, que tiene la siguiente sintaxis:
(function(exports, require, module, __filename, __dirname) { // entire module code lives in here});
- El contenedor de funciones asegura que todo el código escrito dentro de un módulo sea privado a menos que se indique explícitamente lo contrario (exportado). Los parámetros
exports
,require
,module
,__filename
, y__dirname
actúan como las variables globales para todo el código en un módulo. Dado que cada módulo tiene un contenedor de función propio, el código escrito dentro de un contenedor de función se vuelve local para ese contenedor de función (módulo de lectura) y no es accesible dentro de otro contenedor de función (módulo de lectura). module
palabra clave se refiere al objeto que representa el módulo actual. Elmodule
objeto tiene una clave nombradaexports
.module.exports
es otro objeto que se utiliza para definir lo que puede exportar un módulo y puede estar disponible para otros módulos. En resumen, si un módulo desea exportar algo, debe agregarse almodule.exports
objeto.- El valor predeterminado de
module.exports
objeto es{}
. - Hay tres métodos en los que puede exportar algo de un módulo o agregar algo al
module.exports
objeto:1. Defina todas las construcciones primero y luego use múltiples
module.exports
declaraciones donde cada declaración se usa para exportar una construcción.2. Defina primero todas las construcciones y luego use una sola
module.exports
declaración para exportar todas las construcciones a la vez siguiendo la notación literal del objeto.3. Agregue construcciones al
module.exports
objeto mientras las define. require
palabra clave se refiere a una función que se usa para importar todas las variables y funciones exportadas usando elmodule.exports
objeto desde otro módulo. En resumen, si un archivo quiere importar algo, debe declararlo usando la siguiente sintaxis:
require('idOrPathOfModule');
- Al exportar algo de un módulo, puede utilizar cualquier identificador válido. No es obligatorio que necesite dar el nombre exacto de la variable / función como clave de la propiedad agregada al
module.exports
objeto. Solo asegúrese de usar la misma clave para acceder a algo que usó al exportarlo.