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

Moduler

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

For eksempel, hvis du har en fil, der indeholder en kode, og denne fil er navngivet xyz.js, behandles denne fil som et modul i Node, og du kan sige, at du har oprettet et modul med navnet xyz.

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

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

circle.js

Du kan kalde circle.jsfilen til et modul med navnet circle.

Du undrer dig måske over, hvorfor er der behov for at have flere moduler? Du kunne bare have skrevet al koden i et enkelt modul. Nå, det er meget vigtigt at skrive modulær kode. Med modulær mener jeg at sige, at din kode skal være uafhængig og skal være løst koblet. 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 i et modul?

Før koden udføres i et modul, tager Node hele koden og omslutter den i en funktionsindpakning. Syntaksen for denne funktionsomslag er:

Funktionsindpakningen til circlemodulet vil se ud som den nedenfor:

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

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

Dette er den mest betydningsfulde fordel ved at have moduler i Node.js. Selv hvis du definerer en global variabel i et modul hjælp var, leteller constnøgleord, er de variabler virkefelt lokalt til modulet stedet for at blive virkefelt globalt. Dette sker, fordi hvert modul har en egen funktionsindpakning, og koden, der er skrevet i en funktion, er lokal for den funktion og ikke kan tilgås uden for denne funktion.

Forestil dig, at der er to moduler - A og B . Koden er skrevet inde i modul A er indesluttet i funktion indpakning, der svarer til modul A . Lignende ting der sker med den kode skrevet inde i modul B . Da koden, der hører til begge modulerne, er lukket inden for forskellige funktioner, vil disse funktioner ikke være i stand til at få adgang til koden til hinanden. (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 omvendt.

De fem parametre - exports, require, module, __filename, __dirnamefindes inde i hver modul i Node. Selvom disse parametre er globale i forhold til koden i et modul, er de alligevel lokale for modulet (på grund af funktionsomslaget som forklaret ovenfor). Disse parametre giver værdifuld information relateret til et modul.

Lad os besøge circlemodulet, som du kiggede på tidligere. Der er tre konstruktioner defineret i dette modul - en konstant variabel PI, en funktion navngivet calculateAreaog en anden funktion navngivet calculateCircumference. Et vigtigt punkt at huske på er, at alle disse konstruktioner er private for circlemodulet som standard. Det betyder, at du ikke kan bruge disse konstruktioner i noget andet modul, medmindre det er udtrykkeligt angivet.

Så spørgsmålet, der opstår nu, er, hvordan specificerer du noget i et modul, der kan bruges af et andet modul? Dette er, når module& indstillingerne requirefor funktionsomslag er nyttige. Lad os diskutere disse to parametre i denne artikel.

module

Den moduleparameter (snarere et nøgleord i et modul i Node) henviser til det objekt, der repræsenterer den aktuelle modul . exportser en nøgle til moduleobjektet, hvis tilsvarende værdi er et objekt. Standardværdien af module.exportsobjektet er {}(tomt objekt). Du kan kontrollere dette ved at logge værdien af modulenøgleordet i ethvert modul. Lad os kontrollere, hvad der er værdien af moduleparameteren inde i circlemodulet.

circle.js

Bemærk, at der er en console.log(module);erklæring i slutningen af ​​koden i filen ovenfor. Når du ser output, logger det moduleobjektet, som har en nøgle, der er navngivet, exportsog den værdi, der svarer til denne nøgle, er {}(et tomt objekt).

Hvad gør module.exportsobjektet nu? Nå, det bruges til at definere ting, der kan eksporteres af et modul. Uanset hvad der eksporteres fra et modul, kan det igen gøres tilgængeligt for andre moduler. Eksport af noget er ret let. Du skal bare tilføje det til module.exportsobjektet. Der er tre måder at tilføje noget til module.exportsobjektet, der skal eksporteres. Lad os diskutere disse metoder en efter en.

Metode 1:

(Definere konstruktioner og derefter bruge flere module.exportsudsagn 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 aktion og se, hvordan du kan eksportere de to funktioner, der er defineret i circlemodulet.

circle.js

Som jeg fortalte dig tidligere, moduleer et objekt, der har nøglen navngivet, exportsog denne nøgle ( module.exports) til gengæld består af et andet objekt. Nu, hvis du bemærker koden ovenfor, er alt hvad du laver at tilføje nye egenskaber (nøgleværdipar) til module.exportsobjektet.

Den første ejendom har nøglen calculateArea(defineret på linje 19)og værdien skrevet på højre side af tildelingsoperatøren er funktionen defineret med navnet calculateArea(på linje 9).

Den anden egenskab (defineret på linje 20) har nøglen calculateCircumferenceog værdien er funktionen defineret med navnet calculateCircumference(på linje 16).

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

Lad os heller ikke glemme, at du har brugt priknotationen her. Du kan alternativt bruge parentesnotationen til at tildele module.exportsobjektets egenskaber og tilføje funktionerne - calculateAreaog calculateCircumferenceved at specificere tasterne efter parentesnotationen. Således kan du skrive følgende to linjer for at tilføje egenskaber til module.exportsobjektet ved hjælp af parentesnotation, mens du erstatter de sidste to linjer (ved hjælp af punktnotation) i koden ovenfor:

// exporting stuff by adding to module.exports object using the bracket notation
module.exports['calculateArea'] = calculateArea;module.exports['calculateCircumference'] = calculateCircumference; 

Lad os nu prøve at logge module.exportsobjektets værdi efter at have tilføjet egenskaberne. Bemærk, at følgende udsagn tilføjes i slutningen af ​​koden i nedenstående fil:

// logging the contents of module.exports object after adding properties to it
console.log(module.exports);

circle.js

Lad os kontrollere 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 :

node circle

Produktion:

{ calculateArea: [Function: calculateArea], calculateCircumference: [Function: calculateCircumference] }

Konstruktionerne - calculateAreaog calculateCircumference, tilføjet til module.exportsobjektet, logges. Således tilføjede du med succes de to egenskaber i module.exportsobjektet, så funktionerne - calculateAreaog calculateCircumferencekan eksporteres fra circlemodulet til et andet modul.

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

Metode 2:

(Definere konstruktioner og derefter bruge et enkelt module.exportsudsagn til at tilføje egenskaber)

En anden måde er at definere alle konstruktionerne først (som du gjorde i den tidligere metode), men brug en enkelt module.exportserklæring til at eksportere dem alle. Denne metode svarer til syntaksen for objektbogstavelig notation, hvor du tilføjer alle egenskaberne til et objekt på én gang.

Her brugte du objektets bogstavelige notation og tilføjede både funktionerne - calculateArea og calculateCircumference(på én gang) til module.exportsobjektet ved at skrive et enkelt modul . Eksporterklæ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:

(Tilføjelse af egenskaber til module.exportsobjektet, mens konstruktioner defineres)

I denne metode kan du tilføje konstruktionerne til module.exportsobjektet, mens du definerer dem. Lad os se, hvordan denne metode kan anvendes i vores circlemodul.

I ovenstående kode kan du se, at funktionerne i modulet føjes til module.exportsobjektet, når de defineres. Lad os se på, hvordan dette fungerer. Du tilføjer en nøgle calculateAreatil module.exportsobjektet, og værdien, der svarer til denne nøgle, er funktionsdefinitionen.

Bemærk, at funktionen ikke længere har noget navn og er en anonym funktion, som netop behandles som en værdi for en nøgle til et objekt. Således kan der ikke henvises til denne funktion i circlemodulet, og du kan ikke påberåbe sig denne funktion inde i dette modul ved at skrive følgende udsagn:

calculateArea(8);

Hvis du prøver at udføre ovenstående erklæring, får du en ReferenceErrorerklæring calculateArea is not defined.

Nu hvor du har lært, hvordan du kan specificere, hvad der skal eksporteres fra et modul, hvordan tror du, at det andet modul kan 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 har brug for at diskutere et andet navngivet parameter require.

kræve

requirenøgleord refererer til en funktion, der bruges til at importere alle de konstruktioner, der eksporteres ved hjælp af module.exportsobjektet fra et andet modul. Hvis du har et modul x , hvor du eksporterer nogle konstruktioner ved hjælp af module.exportsobjektet, og du vil importere disse eksporterede konstruktioner i modul y , skal du kræve modulet x i modulet y ved hjælp af requirefunktionen. Den værdi, der returneres af requirefunktionen i modul y, er lig med module.exportsobjektet i modulet x .

Lad os forstå dette ved hjælp af eksemplet, som vi diskuterede tidligere. Du har allerede det circlemodul, hvorfra du eksporterer funktionerne, calculateAreaog calculateCircumference. Lad os nu se, hvordan du kan bruge requirefunktionen til at importere de eksporterede ting i et andet modul.

Lad os først oprette en ny fil, hvor du bruger den eksporterede kode fra circlemodulet. Lad os navngive denne fil, app.jsog du kan kalde den appmodulet.

Målet er at importere appal den kode, der eksporteres fra circlemodulet til modulet. Så hvordan kan du medtage din kode skrevet i et modul inde i et andet modul?

Overvej syntaksen for nedenstående requirefunktion:

const variableToHoldExportedStuff = require('idOrPathOfModule');

Den requirefunktion tager i et argument, som kan være et ID eller en sti. ID'et refererer til id (eller navn) på det nødvendige modul. Du skal angive ID som et argument, når du bruger tredjepartsmoduler eller kernemoduler, der leveres af Node Package Manager. På den anden side, når du har defineret brugerdefinerede moduler af dig, skal du angive stien til modulet som argument. Du kan læse mere om den nødvendige funktion fra dette link.

Fordi du allerede har defineret et brugerdefineret modul med navnet circle, giver du stien som et argument til requirefunktionen.

app.js

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

Lad os logge ind på konsollen circlevariablen, som indeholder resultatet returneret af requirefunktionen. 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 nodemoninstalleret pakke):

node app

Produktion:

{ calculateArea: [Function: calculateArea],calculateCircumference: [Function: calculateCircumference] }

Som du kan se, requirereturnerer funktionen et objekt, hvis nøgler er navnene på de variabler / funktioner, der er eksporteret fra det krævede modul ( circle). Kort sagt requirereturnerer funktionen module.exportsobjektet.

Lad os nu få adgang til de funktioner, der er importeret fra circlemodulet.

app.js

Produktion:

Area = 200.96, Circumference = 50.24

Hvad tror du vil ske, hvis jeg prøver at få adgang til den variabel, der er PIdefineret i circlemodulet inde i appmodulet?

app.js

Produktion:

Area = 200.96, Circumference = 50.24pi = undefined

Kan du finde ud af, hvorfor pier det undefined? Dette skyldes, at variablen PIikke eksporteres fra circlemodulet. Husk det punkt, hvor jeg fortalte dig, at du ikke kan få adgang til den kode, der er skrevet inde i et modul i et andet modul, for al den kode, der er skrevet inde i et modul, er privat for det, medmindre det eksporteres? Her forsøger du at få adgang til noget, der ikke er eksporteret fra circlemodulet og er privat for det.

Så du undrer dig måske over, hvorfor du ikke fik en ReferenceError. Dette skyldes, at du forsøger at få adgang til en nøgle med navnet PIinde i module.exportsobjektet, der returneres af requirefunktionen. Du ved også, at den navngivne nøgle PIikke findes i module.exportsobjektet.

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 undefined. Dette er grunden til, at du får PIsom i undefinedstedet for at få en ReferenceError.

Lad os nu eksportere variablen PIfra circlemodulet og se om svaret ændres.

circle.js

Bemærk, at du her ikke bruger navnet på variablen PIsom nøglen til den egenskab, der er føjet til module.exportsobjektet. Du bruger i stedet et andet navn, hvilket er lifeOfPi.

Dette er en interessant ting at bemærke. Når du eksporterer nogle kodningskonstruktioner, kan du give ethvert navn til nøglen, når du tilføjer en egenskab, der er føjet til module.exportsobjektet. Det er ikke obligatorisk at bruge det samme navn som det navn, du brugte, da du definerede 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 bruge en hvilken som helst gyldig identifikator, men på højre side af tildelingsoperatøren skal du angive en værdi, der er defineret som en konstruktion i omfanget af det aktuelle modul (som du har defineret variablerne og funktionerne i modulet 'cirkel').

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

Da du brugte nøglen lifeOfPi, skal du bruge den samme nøgle til at få adgang til den variabel, der er PIdefineret i circlemodulet, som det er gjort i koden ovenfor.

Produktion:

Area = 200.96, Circumference = 50.24pi = 3.14

Hvad tror du vil ske, hvis du bruger navnet på variablen i stedet for at bruge den nøgle, der blev brugt under eksport? Kort sagt, lad os prøve at få adgang til PI(navn på variablen) i stedet for lifeOfPi(nøgle brugt under eksport PI).

app.js

Produktion:

Area = 200.96, Circumference = 50.24pi = undefined

Dette sker, fordi module.exportsobjektet ikke længere kender variablen PI. Det ved bare om de nøgler, der er føjet til det. Da nøglen, der bruges til at eksportere variablen, PIer lifeOfPi, kan sidstnævnte kun bruges til at få adgang til den førstnævnte.

TL; DR

  • Hver fil i Node.js kaldes et modul .
  • Før koden, der er skrevet i et modul, udføres, tager Node.js hele koden, der er skrevet inde i modulet, og konverterer den til en funktionsindpakning, der har følgende syntaks:
(function(exports, require, module, __filename, __dirname) { // entire module code lives in here});
  • Funktionsindpakningen sikrer, at al kode skrevet i et modul er privat for det, medmindre andet udtrykkeligt er angivet (eksporteret). Parametrene exports, require, module, __filename, og __dirnamefungere som variablerne globale for hele kode i et modul. Da hvert modul har en egen funktionsindpakning, bliver koden, der er skrevet inden i en funktionsindpakning, lokal for den funktionsindpakning (læs modul) og er ikke tilgængelig inde i en anden funktionsindpakning (læs modul).
  • modulenøgleord refererer til det objekt, der repræsenterer det aktuelle modul. Det moduleobjekt har en nøgle med navnet exports. module.exportser et andet objekt, der bruges til at definere, hvad der kan eksporteres af et modul og kan gøres tilgængeligt for andre moduler. Kort sagt, hvis et modul ønsker at eksportere noget, skal det føjes til module.exportsobjektet.
  • Standardværdien af module.exportsobjektet er {}.
  • Der er tre metoder, hvor du kan eksportere noget fra et modul eller tilføje noget til module.exportsobjektet:

    1. Definer først alle konstruktioner, og brug derefter flere module.exportsudsagn, hvor hver sætning bruges til at eksportere en konstruktion.

    2. Definer først alle konstruktionerne, og brug derefter en enkelt module.exportssætning til at eksportere alle konstruktioner på én gang efter den bogstavelige objektnotation.

    3. Føj konstruktioner til module.exportsobjektet, mens du definerer dem.

  • requirenøgleord refererer til en funktion, der bruges til at importere alle variabler og funktioner, der eksporteres ved hjælp af module.exportsobjektet fra et andet modul. Kort sagt, hvis en fil vil importere noget, skal den erklære det ved hjælp af følgende syntaks:
require('idOrPathOfModule');
  • Mens du eksporterer noget fra et modul, kan du bruge enhver gyldig identifikator. Det er ikke obligatorisk, at du skal angive det nøjagtige navn på variablen / funktionen som nøglen til den egenskab, der tilføjes til module.exportsobjektet. Bare sørg for at bruge den samme nøgle til at få adgang til noget, som du brugte, mens du eksporterede det.