Alt hvad du skulle vide om 'modul' og 'kræve' i Node.js

moduler

Node.js behandler hver JavaScript-fil som et separat modul.

Hvis du for eksempel har en fil, der indeholder en eller anden kode, og denne fil kaldes xyz.js, behandles denne fil som et modul i Node, og du kan sige, at du har oprettet et modul med navnet xyz.

JavaScript-fil i Node.js svarende til et 'modul'

Lad os tage et eksempel for at forstå dette bedre.

Du har en fil med navnet cirkel.js, som består af logikken til beregning af området og omkredsen af ​​en cirkel med en given radius som angivet nedenfor:

circle.js

Du kan kalde cirkel.js-fil til et modul med navnet cirkel.

Du spekulerer måske på, hvorfor er der behov for flere moduler? Du kunne lige have skrevet al koden i et enkelt modul. Det er meget vigtigt at skrive modulær kode. Med modulær mening vil jeg sige, at din kode skal være uafhængig og bør kobles løst. Forestil dig, at der er et stort program, og at du har al din kode skrevet på ét sted, kun en fil. For rodet, ikke?

Hvordan kører koden, der er skrevet i et modul?

Før udførelse af koden, der er skrevet inde i et modul, tager Node hele koden og lukker den ind i en funktionsindpakning. Syntaks for denne funktionsindpakning er:

Al kode, du skriver i et modul, findes i funktionsindpakningen!

Funktionsomslaget til cirkelmodulet ser ud som det, der er givet nedenfor:

Du kan se, at der er en funktionsindpakning på rodniveau, der omfatter al den kode, der er skrevet inde i cirkelmodulet.

Hele koden, der er skrevet inde i et modul, er privat for modulet, medmindre andet udtrykkeligt er angivet (eksporteret).

Dette er den mest markante fordel ved at have moduler i Node.js. Selv hvis du definerer en global variabel i et modul ved hjælp af var, lad eller const nøgleord, scodes variablerne lokalt til modulet i stedet for at blive scoped globalt. Dette sker, fordi hvert modul har en egen funktionsindpakning, og koden, der er skrevet i en funktion, er lokal for denne funktion og ikke kan fås adgang til uden for denne funktion.

Koden skrevet i et modul er privat for det!

Forestil dig, at der er to moduler - A og B. Koden, der er skrevet inde i modul A, er indesluttet i funktionsindpakningen svarende til modulet A. Lignende ting sker med koden, der er skrevet inde i modulet B. Fordi koden for begge moduler er lukket inden for forskellige funktioner, vil disse funktioner ikke kunne få adgang til hinandens kode. (Husk, at hver funktion i JavaScript har sit eget lokale omfang?) Dette er grunden til, at modul A ikke kan få adgang til koden, der er skrevet inde i modul B og vice versa.

De fem parametre - eksport, kræver, modul, __-filnavn, __ -navn er tilgængelige i hvert modul i Node. Selvom disse parametre er globale for koden i et modul, er de dog lokale for modulet (på grund af funktionsindpakningen som forklaret ovenfor). Disse parametre giver værdifuld information relateret til et modul.

Lad os se på cirkelmodulet, som du kiggede på tidligere. Der er tre konstruktioner defineret i dette modul - en konstant variabel PI, en funktion med navnet calculArea og en anden funktion med navnet calculCircumference. Et vigtigt punkt at huske er, at alle disse konstruktioner er private for cirkelmodulet som standard. Det betyder, at du ikke kan bruge disse konstruktioner i noget andet modul, medmindre det udtrykkeligt er angivet.

Så det spørgsmål, der opstår nu, er, hvordan specificerer du noget i et modul, der kan bruges af et andet modul? Dette er, når modulet & kræver parametre for funktionsindpakningen er nyttigt. Lad os diskutere disse to parametre i denne artikel.

modul

Modulparameteren (snarere et nøgleord i et modul i Node) henviser til det objekt, der repræsenterer det aktuelle modul. eksport er en nøgle til modulobjektet, hvis tilsvarende værdi er et objekt. Standardværdien af ​​module.exports-objektet er {} (tomt objekt). Du kan kontrollere dette ved at logge værdien af ​​modulnøgleordet i ethvert modul. Lad os tjekke, hvad der er værdien af ​​modulparameter inde i cirkelmodulet.

circle.js

Bemærk, at der er en console.log (modul); erklæring i slutningen af ​​koden i filen angivet ovenfor. Når du ser output, vil det logge modulobjektet, der har en nøgle, der hedder eksport, og værdien, der svarer til denne nøgle, er {} (et tomt objekt).

Hvad gør modulet.exports-objektet nu? Det bruges til at definere ting, der kan eksporteres med et modul. Uanset hvad der eksporteres fra et modul kan igen gøres tilgængeligt for andre moduler. Det er ret let at eksportere noget. Du skal bare tilføje det til module.exports-objektet. Der er tre måder at tilføje noget til module.exports-objektet, der skal eksporteres. Lad os diskutere disse metoder én efter én.

Metode 1:
(Definition af konstruktioner og derefter anvendelse af multiple module.exports-udsagn til at tilføje egenskaber)

I den første metode definerer du først konstruktionerne og bruger derefter flere module.exports-udsagn, hvor hver sætning bruges til at eksportere noget fra et modul. Lad os se på denne metode i handling og se, hvordan du kan eksportere de to funktioner, der er defineret i cirkelmodulet.

circle.js

Som jeg fortalte dig tidligere, er modul et objekt med den nøgle, der hedder eksport, og denne nøgle (module.exports) består til gengæld af et andet objekt. Hvis du nu lægger mærke til koden, der er angivet ovenfor, er alt det, du gør, at tilføje nye egenskaber (nøgleværdipar) til objektet module.exports.

Den første egenskab har nøglen calculArea (defineret på linje 19), og værdien skrevet til højre for tildelingsoperatøren er den funktion, der er defineret med navnet calculArea (på linje 9).

Den anden egenskab (defineret på linje 20) har nøglen beregne omkrets, og værdien er den funktion, der er defineret med navnet beregne omkrets (på linje 16).

Således har du tildelt to egenskaber (nøgleværdipar) til objektet module.exports.

Lad os ikke glemme, at du har brugt dot-notationen her. Du kan alternativt bruge konsolnotationen til at tildele egenskaberne til modulet.exports-objekt og tilføje funktionerne - beregneArea og beregne Omkrets ved at specificere tasterne efter parentesnotationen. Således kan du skrive følgende to linjer for at tilføje egenskaber til module.exports-objektet ved hjælp af parentesnotation, mens de to sidste linjer erstattes (ved hjælp af punktnotation) i koden ovenfor:

// eksportere ting ved at tilføje til module.exports-objekt ved hjælp af parentesnotationen
module.exports ['calculArea'] = beregneArea;
module.exports ['calculCircumference'] = beregne Circumference;

Lad os nu prøve at logge værdien af ​​module.exports-objektet efter tilføjelse af egenskaber. Bemærk, at følgende erklæring tilføjes i slutningen af ​​koden i filen nedenfor:

// at logge indholdet af module.exports-objektet efter tilføjelse af egenskaber til det
console.log (module.exports);

circle.js

Lad os tjekke output af denne kode og se, om alt fungerer fint. For at gøre dette skal du gemme din kode og køre følgende kommando i din terminal:

nodekreds

Produktion:

{
   calculArea: [Funktion: calculArea],
   calculCircumference: [Funktion: calculCircumference]
}

Konstruktionerne - calculArea og calculCircumference, tilføjet til module.exports, objekt logges. Således har du med succes tilføjet de to egenskaber i module.exports-objektet, så funktionerne - calculArea og calculCircumference kan eksporteres fra cirkelmodulet til et andet modul.

I denne metode definerede du først alle konstruktioner og brugte derefter multiple module.exports-udsagn, hvor hver sætning bruges til at tilføje en egenskab til module.exports-objektet.

Metode 2:
(Definition af konstruktioner og derefter ved hjælp af en enkelt module.exports-erklæring til at tilføje egenskaber)

En anden måde er at definere alle konstruktioner først (som du gjorde i den tidligere metode), men brug en enkelt module.exports-erklæring til at eksportere dem alle. Denne metode svarer til syntaksen for bogstavelig notation af objekt, hvor du føjer alle egenskaber til et objekt på en gang.

Her brugte du objektets bogstavelige notation og føjede begge funktionerne - beregneArea og calculCircumference (alt på én gang) til module.exports-objektet ved at skrive en enkelt module.exports-erklæring.

Hvis du kontrollerer output af denne kode, får du det samme resultat, som du fik tidligere, når du bruger metode 1.

Metode 3:
(Føj egenskaber til module.exports-objektet, mens konstruktionen defineres)

I denne metode kan du tilføje konstruktioner til objektet module.exports, mens du definerer dem. Lad os se, hvordan denne metode kan bruges i vores cirkelmodul.

I koden ovenfor kan du se, at funktionerne i modulet tilføjes til objektet module.exports, når de defineres. Lad os se på, hvordan dette fungerer. Du tilføjer en nøgle calculArea til module.exports-objektet, og den værdi, der svarer til denne nøgle, er funktionsdefinitionen.

Bemærk, at funktionen ikke længere har noget navn og er en anonym funktion, der bare behandles som en værdi for en nøgle til et objekt. Derfor kan der ikke henvises til denne funktion i cirkelmodulet, og du kan ikke påberåbe dig denne funktion i dette modul ved at skrive følgende sætning:

calculateArea (8);

Hvis du prøver at udføre ovenstående udsagn, får du en ReferenceError med angivelse, at calculArea ikke er defineret.

Nu hvor du har lært, hvordan du kan specificere, hvad der skal eksporteres fra et modul, hvordan tror du, at det andet modul vil være i stand til at bruge de eksporterede ting? Du skal importere modulet til et andet modul for at kunne bruge de eksporterede ting fra førstnævnte i sidstnævnte. Dette er, når vi er nødt til at diskutere en anden parameter, der hedder kræve.

kræve

kræver nøgleord henviser til en funktion, der bruges til at importere alle konstruktioner, der eksporteres ved hjælp af module.exports-objektet fra et andet modul. Hvis du har et modul x, hvor du eksporterer nogle konstruktioner vha. Objektet module.exports, og du vil importere disse eksporterede konstruktioner i modul y, skal du derefter kræve modulet x i modulet y ved hjælp af funktionen kræver. Den værdi, der returneres af den krævede funktion i modul y, er lig med objektet module.exports i modulet x.

kræver funktions returnerer module.exports objekt

Lad os forstå dette ved hjælp af det eksempel, som vi diskuterede tidligere. Du har allerede cirkelmodulet, hvorfra du eksporterer funktionerne calculArea og calculCircumference. Lad os nu se, hvordan du kan bruge den krævede funktion til at importere de eksporterede ting i et andet modul.

Lad os først oprette en ny fil, hvor du vil bruge den eksporterede kode fra cirkelmodulet. Lad os navngive denne fil app.js, og du kan kalde den appmodulet.

Målet er at importere al den kode, der eksporteres fra cirkelmodulet til appmodulet. Så hvordan kan du inkludere din kode skrevet i et modul i et andet modul?

Overvej syntaks for den krævede funktion, der er givet nedenfor:

const variableToHoldExportedStuff = kræve ('idOrPathOfModule');

Funktionen kræver indtager et argument, der kan være et ID eller en sti. ID refererer til id (eller navn) på det nødvendige modul. Du skal angive ID som et argument, når du bruger tredjepartsmoduler eller kernemoduler leveret af Node Package Manager. På den anden side, når du har tilpassede moduler defineret af dig, skal du angive stien til modulet som argumentet. Du kan læse mere om funktionen kræver fra dette link.

Da du allerede har defineret et brugerdefineret modul med navnet cirkel, giver du stien som et argument til den krævede funktion.

app.js

Hvis du tydeligt bemærker, betyder prikken i starten af ​​stien, at det er en relativ sti, og at modulerne app og cirkel er gemt på den samme sti.

Lad os logge ind på konsollen cirkelvariablen, der indeholder resultatet returneret af kravfunktionen. Lad os se hvad der er indeholdt i denne variabel.

app.js

Kontroller output ved at gemme al din kode og køre følgende kommando i din terminal (sidstnævnte er ikke påkrævet, hvis du har en nodemon-pakke installeret):

node app

Produktion:

{calculArea: [Funktion: calculArea],
calculCircumference: [Funktion: calculCircumference]}

Som du kan se, returnerer funktionen kræver et objekt, hvis taster er navnene på de variabler / funktioner, der er eksporteret fra det krævede modul (cirkel). Kort sagt returnerer funktionen kræver objektet module.exports.

Lad os nu få adgang til de funktioner, der importeres fra cirkelmodulet.

app.js

Produktion:

Areal = 200,96, Omkrets = 50,24

Hvad tror du, der vil ske, hvis jeg prøver at få adgang til den variabel, der hedder PI defineret i cirkelmodulet inde i appmodulet?

app.js

Produktion:

Areal = 200,96, Omkrets = 50,24
pi = udefineret

Kan du finde ud af, hvorfor pi er udefineret? Det skyldes, at variablen PI ikke eksporteres fra cirkelmodulet. Husk det punkt, hvor jeg fortalte dig, at du ikke kan få adgang til koden, der er skrevet inde i et modul i et andet modul, for alle koder, der er skrevet inde i et modul, er private for det, medmindre det eksporteres? Her prøver du at få adgang til noget, der ikke er blevet eksporteret fra cirkelmodulet og er privat for det.

Så undrer du dig måske over, hvorfor du ikke fik en ReferenceError. Dette skyldes, at du prøver at få adgang til en nøgle med navnet PI inde i objektet module.exports, der er returneret af funktionen kræver. Du ved også, at nøglen, der hedder PI, ikke findes i objektet module.exports.

Bemærk, at når du prøver at få adgang til en ikke-eksisterende nøgle i et objekt, får du resultatet som udefineret. Dette er grunden til, at du får PI som udefineret i stedet for at få en ReferenceError.

Lad os nu eksportere variablen PI fra cirkelmodulet og se, om svaret ændres.

circle.js

Bemærk, at du her ikke bruger navnet på variablen PI som nøglen til den egenskab, der er tilføjet til module.exports-objektet. Du bruger i stedet et andet navn, som er lifeOfPi.

Dette er en interessant ting at bemærke. Når du eksporterer nogle kodningskonstruktioner, kan du give et vilkårligt navn til nøglen, når du tilføjer en egenskab, der er føjet til module.exports-objektet. Det er ikke obligatorisk at bruge det samme navn som det navn, du brugte under definitionen af ​​konstruktionen. Dette skyldes, at du kan bruge enhver gyldig identifikator som nøglen i et JavaScript-objekt. På venstre side af tildelingsoperatøren kan du således bruge en hvilken som helst gyldig identifikator, men til højre for tildelingsoperatøren skal du angive en værdi, der er defineret som en konstruktion inden for det aktuelle modul (som du har defineret variabler og funktioner i 'cirkel' -modulet).

Et vigtigt punkt, der skal bemærkes, er, at mens du importerer noget fra et andet modul i det aktuelle modul, skal du bruge den samme nøgle, som du brugte, mens du eksporterede det.

app.js

Fordi du brugte nøglen lifeOfPi, skal du bruge den samme nøgle for at få adgang til variablen PI, der er defineret i cirkelmodulet, som det er gjort i koden, der er angivet ovenfor.

Produktion:

Areal = 200,96, Omkrets = 50,24
pi = 3,14

Hvad tror du, der vil ske, hvis du bruger navnet på variablen i stedet for at bruge den nøgle, der blev brugt under eksport? Lad os kort sagt forsøge at få adgang til PI (variabelens navn) i stedet for lifeOfPi (nøgle, der bruges, mens du eksporterer PI).

app.js

Produktion:

Areal = 200,96, Omkrets = 50,24
pi = udefineret

Dette sker, fordi module.exports-objektet ikke kender variablen PI længere. Det ved bare om nøglerne, der er tilføjet til det. Da den nøgle, der bruges til at eksportere variablen PI, er lifeOfPi, kan sidstnævnte kun bruges til at få adgang til førstnævnte.

TL; DR

  • Hver fil i Node.js omtales som et modul.
  • Før du udfører koden, der er skrevet i et modul, tager Node.js hele koden, der er skrevet inde i modulet, og konverterer den til en funktionsindpakning, der har følgende syntaks:
(funktion (eksport, kræver, modul, __ filnavn, __ navn) {
 // hele modulkoden bor her
});
  • Funktionsindpakningen sikrer, at al den kode, der er skrevet inde i et modul, er privat for det, medmindre andet er eksplicit anført (eksporteret). Parametrene, der eksporteres, kræver, modul, __ filnavn og __dirname fungerer som de globale variabler til hele koden i et modul. Da hvert modul har sin egen funktionsindpakning, bliver koden, der er skrevet i et funktionsomslag, lokal for denne funktionsindpakning (læs modul) og er ikke tilgængelig i en anden funktionsindpakning (læs modul).
  • modul nøgleord henviser til det objekt, der repræsenterer det aktuelle modul. Modulobjektet har en nøgle, der hedder eksport. module.exports er et andet objekt, der bruges til at definere, hvad der kan eksporteres af et modul, og som kan stilles til rådighed for andre moduler. Kort sagt, hvis et modul ønsker at eksportere noget, skal det føjes til module.exports-objektet.
  • Standardværdien af ​​module.exports-objektet er {}.
  • Der er tre metoder, hvor du kan eksportere noget fra et modul eller tilføje noget til module.exports-objektet:
    1. Definer først alle konstruktioner, og brug derefter multiple module.exports-udsagn, hvor hver sætning bruges til at eksportere en konstruktion.
    2. Definer først alle konstruktioner, og brug derefter en enkelt module.exports-erklæring til at eksportere alle konstruktioner på én gang efter objektlig bogstavelig notation.
    3. Føj konstruktioner til module.exports-objektet, mens du definerer dem.
  • kræver nøgleord henviser til en funktion, der bruges til at importere alle variabler og funktioner, der eksporteres ved hjælp af module.exports-objektet fra et andet modul. Kort sagt, hvis en fil ønsker at importere noget, skal den erklære den ved hjælp af følgende syntaks:
kræve ( 'idOrPathOfModule');
  • Når du eksporterer noget fra et modul, kan du bruge en gyldig identifikator. Det er ikke obligatorisk, at du skal angive det nøjagtige navn på variablen / funktionen som nøglen til den egenskab, der er tilføjet til module.exports-objektet. Bare sørg for, at du bruger den samme nøgle til at få adgang til noget, du brugte, mens du eksporterede den.