Viss, kas jums jāzina par “moduli” un “pieprasīt” vietnē Node.js

Moduļi

Node.js katru JavaScript failu apstrādā kā atsevišķu moduli.

Piemēram, ja jums ir fails, kas satur kādu kodu, un šis fails ir nosaukts xyz.js, tad šis fails tiek uzskatīts par moduli mezglā, un jūs varat teikt, ka esat izveidojis moduli nosaukumu xyz.

Ņemsim piemēru, lai to labāk saprastu.

Jums ir fails ar nosaukumu, circle.jskas sastāv no loģikas laukuma un noteiktā rādiusa apļa apkārtmēru aprēķināšanai, kā norādīts zemāk:

aplis.js

Jūs varat izsaukt circle.jsfailu par moduli ar nosaukumu circle.

Jums varētu rasties jautājums, kāpēc ir nepieciešami vairāki moduļi? Jūs varētu būt vienkārši ierakstījis visu kodu vienā modulī. Nu, ir ļoti svarīgi rakstīt moduļu kodu. Ar modulāru es gribu teikt, ka jūsu kodam jābūt neatkarīgam un tam jābūt brīvi savienotam. Iedomājieties, ka ir liela lietojumprogramma, un viss kods ir ierakstīts tikai vienā vietā, tikai vienā failā. Pārāk nekārtīgs, vai ne?

Kā darbojas moduļa iekšpusē ierakstītais kods?

Pirms moduļa iekšpusē ierakstītā koda izpildes mezgls paņem visu kodu un ieslēdz funkciju iesaiņojumā. Šīs funkcijas iesaiņotāja sintakse ir šāda:

Funkciju iesaiņotājs circlemodulim izskatīsies kā norādīts zemāk:

Var redzēt, ka sakņu līmenī ir funkciju iesaiņotājs, kas aptver visu circlemoduļa iekšpusē ierakstīto kodu .

Viss kods, kas ierakstīts moduļa iekšpusē, ir moduļa privāts, ja vien nav skaidri norādīts (eksportēts) citādi.

Šī ir vissvarīgākā priekšrocība, ja moduļi atrodas Node.js. Pat ja jūs definētu globālu mainīgo moduli izmanto var, letvai constatslēgvārdus, mainīgie tiek tvērumu lokāli modulim nevis tvērumu pasaulē. Tas notiek tāpēc, ka katram modulim ir savs funkciju aptinējs un vienas funkcijas iekšpusē ierakstītais kods ir lokāls šai funkcijai un tam nevar piekļūt ārpus šīs funkcijas.

Iedomājieties, ka ir divi moduļi - un B . Kods rakstīts iekšpusē A modulis tiek ielikta funkciju wrapper, kas atbilst A modulis . Līdzīgi notiek ar kodu, kas ierakstīts moduļa B iekšpusē . Tā kā kods, kas attiecas uz abiem moduļiem, ir ietverts dažādās funkcijās, šīs funkcijas nevarēs piekļūt viens otra kodam. (Atcerieties, ka katrai JavaScript funkcijai ir sava lokālā darbības joma?) Tas ir iemesls, kāpēc A modulis nevar piekļūt kodam B ierakstītajam kodam un otrādi.

Pieci parametri - exports, require, module, __filename, __dirnameir pieejami iekšpusē katram modulim Node. Lai gan šie parametri ir globāli moduļa kodam, tomēr tie ir moduļa lokāli (funkciju iesaiņotāja dēļ, kā paskaidrots iepriekš). Šie parametri sniedz vērtīgu informāciju, kas saistīta ar moduli.

Apskatīsim circlemoduli, kuru apskatījāt iepriekš. Šajā modulī ir definētas trīs konstrukcijas - konstants mainīgais PI, nosaukta funkcija calculateAreaun vēl viena funkcija nosaukta calculateCircumference. Svarīgs jautājums, kas jāpatur prātā, ir tas, ka visi šie konstrukti circlepēc noklusējuma ir moduļa privāti . Tas nozīmē, ka šos konstruktus nevar izmantot nevienā citā modulī, ja vien tas nav skaidri norādīts.

Tātad, tagad rodas jautājums, kā jūs modulī norādāt kaut ko tādu, ko var izmantot kāds cits modulis? Tas ir tad , kad funkciju iesaiņotāja module& requireparametri ir noderīgi. Apskatīsim šos divus parametrus šajā rakstā.

module

moduleParametrs (drīzāk atslēgvārds modulī mezglā) attiecas uz objektu, kas pārstāv pašreizējo moduli . exportsir moduleobjekta atslēga , kuras atbilstošā vērtība ir objekts. module.exportsObjekta noklusējuma vērtība ir {}(tukšs objekts). To var pārbaudīt, reģistrējot moduleatslēgvārda vērtību jebkurā modulī. Pārbaudīsim, kāda ir moduleparametra vērtība circlemoduļa iekšpusē .

aplis.js

Ievērojiet, ka console.log(module);iepriekš norādītajā failā koda beigās ir paziņojums. Kad redzat izvadi, tā reģistrēs moduleobjektu, kuram ir nosaukta atslēga, exportsun šai atslēgai atbilstošā vērtība ir {}(tukšs objekts).

Ko tagad dara module.exportsobjekts? Nu, to izmanto, lai definētu lietas, kuras modulis var eksportēt. Jebkuru no moduļa eksportēto var padarīt pieejamu citiem moduļiem. Kaut ko eksportēt ir diezgan viegli. Jums tas vienkārši jāpievieno module.exportsobjektam. Ir trīs veidi, kā kaut ko pievienot module.exportseksportējamajam objektam. Apspriedīsim šīs metodes pa vienam.

1. metode:

(Konstrukciju definēšana un pēc tam module.exportsrekvizītu pievienošanai vairāku apgalvojumu izmantošana)

Pirmajā metodē vispirms definējat konstrukcijas un pēc tam izmantojiet vairākus module.exports priekšrakstus, kur katrs priekšraksts tiek izmantots, lai kaut ko eksportētu no moduļa. Apskatīsim šo metodi darbībā un redzēsim, kā jūs varat eksportēt divas circlemodulī definētās funkcijas .

aplis.js

Kā es jums teicu iepriekš, moduleir objekts, kura atslēga ir nosaukta, exportsun šī atslēga ( module.exports), savukārt, sastāv no cita objekta. Tagad, ja pamanāt iepriekš norādīto kodu, viss, ko jūs darāt, ir pievienot module.exportsobjektam jaunus rekvizītus (atslēgu un vērtību pārus) .

Pirmajam īpašumam ir atslēga calculateArea(noteikts 19. rindā)un vērtība, kas uzrakstīta piešķiršanas operatora labajā pusē, ir funkcija, kas definēta ar nosaukumu calculateArea(9. rindā).

Otrajam rekvizītam (definēts 20. rindā) ir atslēga calculateCircumferenceun vērtība ir funkcija, kas definēta ar nosaukumu calculateCircumference(16. rindā).

Tādējādi module.exportsobjektam esat piešķīris divas īpašības (atslēgu un vērtību pārus) .

Neaizmirsīsim arī to, ka šeit esat lietojis punktu apzīmējumu. Varat arī izmantot iekavu apzīmējumu, lai piešķirtu module.exportsobjektam rekvizītus un pievienotu funkcijas, calculateAreacalculateCircumferencearī norādot taustiņus pēc iekavas apzīmējuma. Tādējādi jūs varat uzrakstīt šādas divas rindas, lai module.exportsobjektam pievienotu īpašības, izmantojot iekavu apzīmējumus, vienlaikus aizstājot pēdējās divas rindas (izmantojot punktu apzīmējumu) iepriekš norādītajā kodā:

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

Mēģināsim tagad reģistrēt objekta vērtību module.exportspēc rekvizītu pievienošanas. Ievērojiet, ka zemāk esošajā failā koda beigās tiek pievienots šāds paziņojums:

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

aplis.js

Pārbaudīsim šī koda izvadi un redzēsim, vai viss darbojas labi. Lai to izdarītu, saglabājiet kodu un savā terminālā izpildiet šādu komandu :

node circle

Izeja:

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

Konstrukcijas - calculateAreaun calculateCircumference, kas pievienotas module.exportsobjektam, tiek reģistrētas. Tādējādi jūs module.exportsobjektā veiksmīgi pievienojāt abas īpašības, lai funkcijas - calculateAreaun calculateCircumferencevarētu eksportēt no circlemoduļa uz kādu citu moduli.

Šajā metodē vispirms definējāt visus konstruktus un pēc tam izmantojāt vairākus module.exports priekšrakstus, kur katrs apgalvojums tiek izmantots, lai module.exportsobjektam pievienotu rekvizītu .

2. metode:

(Konstrukciju definēšana un pēc tam module.exportsrekvizītu pievienošana ar vienu paziņojumu)

Vēl viens veids ir vispirms definēt visus konstruktus (kā jūs to darījāt iepriekšējā metodē), bet module.exportsvisu eksportēšanai izmantojiet vienu paziņojumu. Šī metode ir līdzīga objekta burtiskā apzīmējuma sintaksei, kurā objektam pievienojat visas īpašības vienlaikus.

Šeit jūs izmantojāt objekta burtisko apzīmējumu un objektam pievienojāt gan funkcijas - calculateArea gan calculateCircumference(visas uzreiz) module.exports, uzrakstot vienu moduli.eksporta paziņojumu.

Pārbaudot šī koda izvadi, iegūsiet tādu pašu rezultātu kā agrāk, izmantojot 1. metodi.

3. metode:

(Īpašību pievienošana module.exportsobjektam, definējot konstrukcijas)

Šajā metodē module.exportsobjektam var pievienot konstrukcijas, tos definējot. Apskatīsim, kā šo metodi var izmantot mūsu circlemodulī.

Iepriekš norādītajā kodā jūs varat redzēt, ka moduļa funkcijas tiek pievienotas module.exportsobjektam, kad tās tiek definētas. Apskatīsim, kā tas darbojas. Jūs objektam pievienojat atslēgu calculateArea, module.exportsun šai atslēgai atbilstošā vērtība ir funkcijas definīcija.

Ņemiet vērā, ka funkcijai vairs nav nosaukuma un tā ir anonīma funkcija, kuru vienkārši uzskata par objekta atslēgas vērtību. Tādējādi circlemodulī nevar atsaukties uz šo funkciju, un šo moduli nevar izsaukt, ierakstot šādu paziņojumu:

calculateArea(8);

Ja jūs mēģināt izpildīt iepriekš minēto paziņojumu, jūs saņemsiet ReferenceErrorpaziņojumu calculateArea is not defined.

Tagad, kad esat uzzinājis, kā jūs varat norādīt, kas jāeksportē no moduļa, kā jūs domājat, kā otrs modulis varēs izmantot eksportēto saturu? Jums ir jāimportē modulis uz kādu citu moduli, lai varētu izmantot eksportētos materiālus no pirmā. Tas ir tad, kad mums jāapspriež cits nosaukums ar nosaukumu require.

pieprasīt

requireatslēgvārds attiecas uz funkciju, kuru izmanto, lai importētu visus module.exportsobjektus eksportētos objektus no cita moduļa. Ja jums ir modulis x , kurā jūs eksportējat dažus module.exportsobjektus, izmantojot objektu, un vēlaties importēt šos eksportētos konstruktus y modulī , tad, izmantojot funkciju , jums jāpieprasa modulis x modulī yrequire . Funkcijas atgrieztā vērtība requiremodulī y ir vienāda ar module.exportsmoduļa x objektu .

Sapratīsim to, izmantojot iepriekš apspriesto piemēru. Jums jau ir circlemodulis, no kura eksportējat funkcijas calculateAreaun calculateCircumference. Apskatīsim, kā jūs varat izmantot requirefunkciju, lai importētu eksportētos materiālus citā modulī.

Vispirms izveidosim jaunu failu, kurā izmantosiet eksportēto kodu no circlemoduļa. Nosauksim šo failu, app.jsun jūs to varat saukt par appmoduli.

Mērķis ir importēt appmodulī visu no circlemoduļa eksportēto kodu . Tātad, kā jūs varat iekļaut vienā modulī ierakstīto kodu cita moduļa iekšpusē?

Apsveriet tālāk norādītās requirefunkcijas sintaksi :

const variableToHoldExportedStuff = require('idOrPathOfModule');

requireFunkcija uzņem argumentu, kas var būt ID, vai ceļš. ID attiecas uz nepieciešamā moduļa ID (vai nosaukumu). Jums ir jānorāda ID kā arguments, ja izmantojat mezglu pakotņu pārvaldnieka piedāvātos trešo pušu moduļus vai galvenos moduļus. No otras puses, kad jums ir definēti pielāgoti moduļi, kā arguments jānorāda moduļa ceļš. No šīs saites varat uzzināt vairāk par funkciju pieprasīt.

Tā kā jūs jau esat definējis pielāgotu moduli ar nosaukumu circle, jūs kā argumentu requirefunkcijai norādīsit ceļu .

app.js

Ja pamanāt skaidri, punkts ceļa sākumā nozīmē, ka tas ir relatīvs ceļš un ka moduļi appun circletiek glabāti tajā pašā ceļā.

Piesakīsimies konsolē circlemainīgajam, kurā ir requirefunkcijas atgrieztais rezultāts . Apskatīsim, kas atrodas šajā mainīgajā.

app.js

Pārbaudiet izvadi, saglabājot visu kodu un terminālā izpildot šādu komandu (ja nodemonpakete ir instalēta, pēdējā nav nepieciešama ):

node app

Izeja:

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

Kā redzat, requirefunkcija atgriež objektu, kura atslēgas ir mainīgo / funkciju nosaukumi, kas eksportēti no nepieciešamā moduļa ( circle). Īsāk sakot, requirefunkcija atgriež module.exportsobjektu.

Tagad piekļūsim funkcijām, kas importētas no circlemoduļa.

app.js

Izeja:

Area = 200.96, Circumference = 50.24

Ko jūs domājat, kas notiks, ja es mēģinātu piekļūt mainīgo nosaukumu PInoteikts circlemodulī iekšpusē appmoduli?

app.js

Izeja:

Area = 200.96, Circumference = 50.24pi = undefined

Vai jūs varat saprast, kāpēc piir undefined? Nu, tas ir tāpēc, ka mainīgais PInetiek eksportēts no circlemoduļa. Atcerieties brīdi, kad es jums teicu, ka jūs nevarat piekļūt kodam, kas ierakstīts moduļa iekšienē citā modulī, jo viss moduļa iekšpusē ievadītais kods ir privāts, ja vien tas netiek eksportēts? Šeit jūs mēģināt piekļūt kaut kam, kas nav eksportēts no circlemoduļa un ir privāts tam.

Tātad, jums var būt jautājums, kāpēc jūs nesaņēmāt ReferenceError. Tas notiek tāpēc, ka jūs mēģināt piekļūt taustiņam, kas nosaukts objekta PIiekšpusē, kuru module.exportsatguvusi requirefunkcija. Jūs arī zināt, ka nosaukta atslēga objektā PInepastāv module.exports.

Ņemiet vērā, ka, mēģinot piekļūt objektā neesošai atslēgai, rezultāts tiek iegūts kā undefined. Tas ir iemesls, kāpēc jūs saņemat PIkā, undefinednevis iegūstat ReferenceError.

Tagad eksportēsim mainīgo PIno circlemoduļa un pārbaudīsim, vai atbilde mainās.

aplis.js

Ievērojiet, ka šeit jūs neizmantojat mainīgā nosaukumu PImodule.exportsobjektam pievienotā rekvizīta atslēgu . Tā vietā jūs izmantojat citu vārdu, kas ir lifeOfPi.

Šī ir interesanta lieta, kas jāatzīmē. Eksportējot kādu kodēšanas konstrukciju, pievienojot module.exportsobjektam pievienotu rekvizītu, atslēgai varat piešķirt jebkuru nosaukumu . Definējot konstrukciju, nav obligāti jāizmanto tas pats nosaukums, kuru izmantojāt. Tas ir tāpēc, ka jūs varat izmantot jebkuru derīgu identifikatoru kā atslēgu JavaScript objektā. Tādējādi piešķiršanas operatora kreisajā pusē varat izmantot jebkuru derīgu identifikatoru, bet piešķiršanas operatora labajā pusē ir jānorāda vērtība, kas pašreizējā moduļa darbības jomā ir definēta kā konstrukcija (kā jūs “mēs esam definējuši mainīgos un funkcijas modulī“ aplis ”.

Svarīgi atzīmēt, ka, importējot kaut ko no cita pašreizējā moduļa moduļa, jums jāizmanto tā pati atslēga, kuru izmantojāt, eksportējot to.

app.js

Tā kā jūs izmantojāt atslēgu lifeOfPi, jums ir jāizmanto tā pati atslēga, lai piekļūtu modulī PIdefinētajam mainīgajam circle, kā tas tiek darīts iepriekš dotajā kodā.

Izeja:

Area = 200.96, Circumference = 50.24pi = 3.14

Kā jūs domājat, kas notiks, ja izmantosiet mainīgā nosaukumu, nevis izmantosiet atslēgu, kas tika izmantota eksportēšanas laikā? Īsāk sakot, mēģināsim piekļūt PI(mainīgā nosaukums) vietā lifeOfPi(atslēga, kas izmantota eksportēšanas laikā PI).

app.js

Izeja:

Area = 200.96, Circumference = 50.24pi = undefined

Tas notiek tāpēc, ka module.exportsobjekts vairs nezina mainīgo PI. Tā vienkārši zina par pievienotajām atslēgām. Tā kā mainīgā eksportēšanai PItiek izmantota atslēga lifeOfPi, pēdējo var izmantot tikai, lai piekļūtu pirmajam.

TL; DR

  • Katrs fails Node.js tiek saukts par moduli .
  • Pirms modulī ierakstītā koda izpildes Node.js paņem visu moduļa iekšpusē ierakstīto kodu un pārveido to par funkciju iesaiņotāju, kuram ir šāda sintakse:
(function(exports, require, module, __filename, __dirname) { // entire module code lives in here});
  • Funkciju iesaiņotājs nodrošina, ka viss moduļa iekšpusē ierakstītais kods tam ir privāts, ja vien nav skaidri norādīts citādi (eksportēts). Parametri exports, require, module, __filename, un __dirnamedarbojas kā mainīgajiem globālo visai kodu moduli. Tā kā katram modulim ir savs funkciju iesaiņotājs, vienā funkciju iesaiņotājā ierakstītais kods kļūst lokāls šim funkciju iesaiņotājam (lasīšanas modulis) un nav pieejams citā funkciju iesaiņotājā (lasīšanas modulis).
  • moduleatslēgvārds attiecas uz objektu, kas pārstāv pašreizējo moduli. moduleObjekts ir atslēga nosaukts exports. module.exportsir vēl viens objekts, ko izmanto, lai noteiktu, ko modulis var eksportēt, un to var padarīt pieejamu citiem moduļiem. Īsāk sakot, ja modulis vēlas kaut ko eksportēt, tas jāpievieno module.exportsobjektam.
  • module.exportsObjekta noklusējuma vērtība ir {}.
  • Ir trīs metodes, kā jūs varat kaut ko eksportēt no moduļa vai kaut ko pievienot module.exportsobjektam:

    1. Vispirms definējiet visus konstruktus un pēc tam izmantojiet vairākus module.exportsapgalvojumus, kur katrs apgalvojums tiek izmantots konstrukcijas eksportēšanai.

    2. Vispirms definējiet visus konstruktus un pēc tam izmantojiet vienu module.exportspaziņojumu, lai eksportētu visus konstruktus uzreiz pēc objekta burtiskā apzīmējuma.

    3. Pievienojiet module.exportsobjektam konstrukcijas, tās definējot.

  • requireatslēgvārds attiecas uz funkciju, kuru izmanto, lai importētu visus mainīgos un funkcijas, kas eksportēti, izmantojot module.exportsobjektu, no cita moduļa. Īsāk sakot, ja fails vēlas kaut ko importēt, tas ir jādeklarē, izmantojot šādu sintaksi:
require('idOrPathOfModule');
  • Eksportējot kaut ko no moduļa, varat izmantot jebkuru derīgu identifikatoru. Nav obligāti jānorāda precīzs mainīgā / funkcijas nosaukums kā module.exportsobjektam pievienotās rekvizīta atslēga . Vienkārši pārliecinieties, vai izmantojat to pašu atslēgu, lai piekļūtu kaut kam, ko izmantojāt, eksportējot to.