Semua yang anda mesti ketahui mengenai 'modul' & 'memerlukan' di Node.js

Modul

Node.js memperlakukan setiap fail JavaScript sebagai modul yang berasingan.

Sebagai contoh, jika anda mempunyai fail yang mengandungi beberapa kod dan nama xyz.jsfile ini, file ini akan dianggap sebagai modul di Node, dan anda boleh mengatakan bahawa anda telah membuat modul bernama xyz.

Mari kita ambil contoh untuk memahami perkara ini dengan lebih baik.

Anda mempunyai fail bernama circle.jsyang terdiri dari logik untuk menghitung luas & keliling bulatan jejari tertentu, seperti yang diberikan di bawah:

bulatan.js

Anda boleh memanggil circle.jsfail modul bernama circle.

Anda mungkin tertanya-tanya mengapa perlu mempunyai banyak modul? Anda mungkin hanya menulis semua kod dalam satu modul. Baiklah, sangat penting untuk menulis kod modular. Secara modular, saya bermaksud mengatakan bahawa kod anda harus bebas dan harus digabungkan secara longgar. Bayangkan bahawa terdapat aplikasi yang besar dan anda mempunyai semua kod anda ditulis di satu tempat, hanya satu fail. Terlalu tidak kemas, bukan?

Bagaimana kod yang ditulis di dalam modul dijalankan?

Sebelum menjalankan kod yang ditulis di dalam modul, Node mengambil keseluruhan kod dan memasukkannya ke dalam pembungkus fungsi. Sintaks pembungkus fungsi ini adalah:

Pembungkus fungsi untuk circlemodul akan kelihatan seperti yang diberikan di bawah:

Anda dapat melihat bahawa ada pembungkus fungsi di peringkat root yang merangkumi semua kod yang ditulis di dalam circlemodul.

Keseluruhan kod yang ditulis di dalam modul adalah tertutup untuk modul, kecuali dinyatakan secara eksplisit (dieksport) sebaliknya.

Ini adalah kelebihan yang paling ketara kerana memiliki modul di Node.js. Walaupun anda menentukan pemboleh ubah global dalam modul menggunakan var, letatau constkata kunci, pemboleh ubah tersebut dilingkari secara tempatan ke modul daripada dilingkupi secara global. Ini berlaku kerana setiap modul mempunyai fungsi pembungkus sendiri dan kod yang ditulis di dalam satu fungsi sesuai dengan fungsi tersebut dan tidak dapat diakses di luar fungsi ini.

Bayangkan bahawa terdapat dua modul - A dan B . Kod tertulis di dalam modul A dikurung dalam fungsi wrapper sepadan dengan modul . Perkara yang sama berlaku dengan hurufiah di dalam modul B . Oleh kerana kod yang berkaitan dengan kedua-dua modul tersebut dilampirkan dalam fungsi yang berlainan, fungsi-fungsi ini tidak akan dapat mengakses kod satu sama lain. (Ingat setiap fungsi dalam JavaScript mempunyai ruang lingkup tempatannya sendiri?) Inilah sebab mengapa modul A tidak dapat mengakses kod yang tertulis di dalam modul B dan sebaliknya.

Lima parameter - exports, require, module, __filename, __dirnameyang ada di dalam setiap modul dalam Nod. Walaupun parameter ini bersifat global untuk kod dalam modul namun sesuai dengan modul (kerana fungsi pembungkus seperti yang dijelaskan di atas). Parameter ini memberikan maklumat berharga yang berkaitan dengan modul.

Mari kita kaji semula circlemodul, yang anda lihat sebelumnya. Terdapat tiga konstruk yang ditentukan dalam modul ini - pemboleh ubah tetap PI, fungsi dinamakan calculateAreadan fungsi lain dinamakan calculateCircumference. Perkara penting yang perlu diingat adalah bahawa semua konstruk ini adalah peribadi untuk circlemodul secara lalai. Ini bermaksud bahawa anda tidak boleh menggunakan konstruk ini dalam modul lain kecuali dinyatakan secara eksplisit.

Oleh itu, persoalan yang timbul sekarang ialah bagaimana anda menentukan sesuatu dalam modul yang boleh digunakan oleh beberapa modul lain? Ini adalah ketika module& requireparameter fungsi pembungkus berfungsi. Mari kita bincangkan dua parameter ini dalam artikel ini.

module

The moduleparameter (bukan kata kunci dalam modul di Node) merujuk kepada objek yang mewakili modul semasa . exportsadalah kunci moduleobjek, yang nilai yang sesuai adalah objek. Nilai lalai module.exportsobjek adalah {}(objek kosong). Anda boleh menyemaknya dengan mencatat nilai modulekata kunci di dalam mana-mana modul. Mari kita periksa berapa nilai moduleparameter di dalam circlemodul.

bulatan.js

Perhatikan bahawa terdapat console.log(module);pernyataan di akhir kod dalam fail yang diberikan di atas. Apabila anda melihat output, ia akan mencatat moduleobjek, yang mempunyai kunci bernama exportsdan nilai yang sesuai dengan kunci ini adalah {}(objek kosong).

Sekarang, apa yang module.exportsdilakukan objek itu? Ia digunakan untuk menentukan perkara yang boleh dieksport oleh modul. Apa sahaja yang dieksport dari modul boleh, pada gilirannya, tersedia untuk modul lain. Mengeksport sesuatu agak mudah. Anda hanya perlu menambahkannya ke module.exportsobjek. Terdapat tiga cara untuk menambahkan sesuatu ke module.exportsobjek yang akan dieksport. Mari kita bincangkan kaedah ini satu persatu.

Kaedah 1:

(Mendefinisikan konstruk dan kemudian menggunakan beberapa module.exportspernyataan untuk menambahkan sifat)

Dalam kaedah pertama, anda menentukan konstruk terlebih dahulu dan kemudian menggunakan beberapa modul. Mengeksport penyataan di mana setiap pernyataan digunakan untuk mengeksport sesuatu dari modul. Mari lihat kaedah ini dalam tindakan dan lihat bagaimana anda dapat mengeksport dua fungsi yang ditentukan dalam circlemodul.

bulatan.js

Seperti yang saya katakan sebelumnya, moduleadalah objek yang mempunyai kunci bernama exportsdan kunci ini ( module.exports), pada gilirannya, terdiri daripada objek lain. Sekarang, jika anda melihat kod yang diberikan di atas, semua yang anda lakukan adalah menambahkan sifat baru (pasangan nilai-kunci) ke module.exportsobjek.

Harta pertama mempunyai kunci calculateArea(ditakrifkan pada baris 19)dan nilai yang ditulis di sebelah kanan pengendali tugasan adalah fungsi yang ditentukan dengan nama calculateArea(pada baris 9).

Harta kedua (ditakrifkan pada baris 20) mempunyai kunci calculateCircumferencedan nilai adalah fungsi yang ditentukan dengan nama calculateCircumference(pada baris 16).

Oleh itu, anda telah menetapkan dua sifat (pasangan nilai-kunci) ke module.exportsobjek.

Jangan lupa bahawa anda telah menggunakan notasi titik di sini. Anda boleh menggunakan notasi tanda kurung untuk menetapkan sifat ke module.exportsobjek dan menambahkan fungsinya - calculateAreadan calculateCircumferencedengan menentukan kunci berikut notasi tanda kurung. Oleh itu, anda boleh menulis dua baris berikut untuk menambahkan sifat ke module.exportsobjek menggunakan notasi kurungan sambil mengganti dua baris terakhir (menggunakan notasi titik) dalam kod yang diberikan di atas:

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

Mari sekarang cuba mencatat nilai module.exportsobjek setelah menambahkan sifat. Perhatikan bahawa pernyataan berikut ditambahkan pada akhir kod dalam fail yang diberikan di bawah:

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

bulatan.js

Mari periksa output kod ini dan lihat apakah semuanya berjalan lancar. Untuk melakukan ini, simpan kod anda dan jalankan arahan berikut di Terminal anda :

node circle

Pengeluaran:

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

Konstruk - calculateAreadan calculateCircumference, ditambahkan ke module.exports, objek dicatat. Oleh itu, anda berjaya menambahkan dua sifat dalam module.exportsobjek sehingga fungsi - calculateAreadan calculateCircumferencedapat dieksport dari circlemodul ke modul lain.

Dalam kaedah ini, anda pertama kali menentukan semua konstruk dan kemudian menggunakan beberapa modul. Mengeksport penyataan di mana setiap pernyataan digunakan untuk menambahkan harta benda ke module.exportsobjek.

Kaedah 2:

(Mendefinisikan konstruk dan kemudian menggunakan satu module.exportspenyataan untuk menambahkan sifat)

Cara lain ialah menentukan semua konstruk terlebih dahulu (seperti yang anda lakukan dalam kaedah sebelumnya) tetapi gunakan satu module.exportspenyataan untuk mengeksport semuanya. Kaedah ini serupa dengan sintaks notasi literal objek di mana anda menambahkan semua sifat ke objek sekaligus.

Di sini, anda menggunakan notasi literal objek dan menambahkan kedua fungsi - calculateArea dan calculateCircumference(sekaligus) ke module.exportsobjek dengan menulis satu pernyataan modul.eksport .

Sekiranya anda memeriksa output kod ini, anda akan mendapat hasil yang sama seperti yang anda dapatkan sebelumnya semasa menggunakan kaedah 1.

Kaedah 3:

(Menambah sifat ke module.exportsobjek semasa menentukan konstruk)

Dalam kaedah ini, anda boleh menambahkan konstruk ke module.exportsobjek sambil menentukannya. Mari lihat bagaimana kaedah ini dapat diguna pakai dalam circlemodul kami .

Dalam kod yang diberikan di atas, anda dapat melihat bahawa fungsi-fungsi dalam modul ditambahkan ke module.exportsobjek ketika mereka ditentukan. Mari lihat bagaimana ini berfungsi. Anda menambah kunci calculateAreake module.exportsobjek dan nilai yang sesuai dengan kunci ini adalah definisi fungsi.

Perhatikan bahawa fungsi tidak lagi mempunyai nama dan merupakan fungsi anonim yang hanya dianggap sebagai nilai pada kunci objek. Oleh itu, fungsi ini tidak dapat dirujuk dalam circlemodul dan anda tidak boleh menggunakan fungsi ini di dalam modul ini dengan menulis pernyataan berikut:

calculateArea(8);

Jika anda cuba untuk melaksanakan kenyataan di atas, anda akan mendapat ReferenceErrormenyatakan calculateArea is not defined.

Setelah anda mengetahui bagaimana anda dapat menentukan apa yang perlu dieksport dari modul, bagaimana anda fikir modul lain akan dapat menggunakan barang yang dieksport? Anda perlu mengimport modul ke beberapa modul lain agar dapat menggunakan barang yang dieksport dari yang pertama pada yang terakhir. Ini adalah ketika kita perlu membincangkan parameter lain bernama require.

memerlukan

requirekata kunci merujuk kepada fungsi yang digunakan untuk mengimport semua konstruk yang dieksport menggunakan module.exportsobjek dari modul lain. Sekiranya anda mempunyai modul x di mana anda mengeksport beberapa konstruk menggunakan module.exportsobjek dan anda ingin mengimport konstruk yang dieksport ini dalam modul y , anda kemudian memerlukan modul x dalam modul y menggunakan requirefungsi tersebut. Nilai yang dikembalikan oleh requirefungsi dalam modul y sama dengan module.exportsobjek dalam modul x .

Mari fahami ini menggunakan contoh yang telah kita bincangkan sebelumnya. Anda sudah mempunyai circlemodul dari mana anda mengeksport fungsi calculateAreadan calculateCircumference. Sekarang, mari kita lihat bagaimana anda boleh menggunakan requirefungsi untuk mengimport barang yang dieksport ke modul lain.

Mari buat dahulu fail baru di mana anda akan menggunakan kod yang dieksport dari circlemodul. Mari namakan fail ini app.jsdan anda boleh memanggilnya appmodul.

Objektifnya adalah untuk memasukkan ke dalam appmodul semua kod yang dieksport dari circlemodul. Jadi, bagaimana anda boleh memasukkan kod anda yang ditulis dalam satu modul di dalam modul yang lain?

Pertimbangkan sintaks requirefungsi yang diberikan di bawah:

const variableToHoldExportedStuff = require('idOrPathOfModule');

Yang requirefungsi mengambil masa dalam hujah yang boleh menjadi ID atau jalan. ID merujuk kepada id (atau nama) modul yang diperlukan. Anda harus memberikan ID sebagai hujah semasa anda menggunakan modul pihak ketiga atau modul teras yang disediakan oleh Pengurus Pakej Node. Sebaliknya, apabila anda mempunyai modul khusus yang ditentukan oleh anda, anda harus memberikan jalan modul sebagai hujah. Anda boleh membaca lebih lanjut mengenai fungsi memerlukan dari pautan ini.

Kerana anda sudah menentukan modul khusus yang dinamakan circle, anda akan memberikan jalan sebagai argumen untuk requirefungsi tersebut.

app.js

Sekiranya anda melihat dengan jelas, titik di permulaan jalan bermaksud bahawa ia adalah jalan relatif dan modul appdan circledisimpan di jalan yang sama.

Mari log masuk ke konsol circlepemboleh ubah, yang mengandungi hasil yang dikembalikan oleh requirefungsi. Mari lihat apa yang terdapat di dalam pemboleh ubah ini.

app.js

Periksa output dengan menyimpan semua kod anda dan jalankan perintah berikut di Terminal anda (yang terakhir tidak diperlukan jika anda sudah nodemonmemasang pakej):

node app

Pengeluaran:

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

Seperti yang anda lihat, requirefungsi mengembalikan objek, yang kuncinya adalah nama pemboleh ubah / fungsi yang telah dieksport dari modul yang diperlukan ( circle). Ringkasnya, requirefungsi mengembalikan module.exportsobjek.

Sekarang mari kita mengakses fungsi yang diimport dari circlemodul.

app.js

Pengeluaran:

Area = 200.96, Circumference = 50.24

Apa yang anda fikir akan berlaku jika saya cuba mengakses pemboleh ubah yang dinamakan PIdalam circlemodul di dalam appmodul?

app.js

Pengeluaran:

Area = 200.96, Circumference = 50.24pi = undefined

Bolehkah anda memikirkan mengapa piadalah undefined? Ini kerana pemboleh ubah PItidak dieksport dari circlemodul. Ingat titik di mana saya memberitahu anda bahawa anda tidak dapat mengakses kod yang ditulis di dalam modul di modul lain kerana semua kod yang ditulis di dalam modul adalah rahsia kecuali dieksport? Di sini, anda cuba mengakses sesuatu yang belum dieksport dari circlemodul dan bersifat peribadi untuknya.

Jadi, anda mungkin tertanya-tanya mengapa anda tidak mendapat ReferenceError. Ini kerana anda cuba mengakses kunci yang dinamakan PIdi dalam module.exportsobjek yang dikembalikan oleh requirefungsi. Anda juga tahu bahawa kunci yang dinamakan PItidak ada pada module.exportsobjek.

Perhatikan bahawa semasa anda cuba mengakses kunci yang tidak ada dalam objek, anda akan mendapat hasilnya sebagai undefined. Inilah sebab mengapa anda mendapat PIdan undefinedbukannya mendapatkan ReferenceError.

Sekarang, mari kita eksport pemboleh ubah PIdari circlemodul dan lihat apakah jawapannya berubah.

bulatan.js

Perhatikan bahawa di sini, anda tidak menggunakan nama pemboleh ubah PIsebagai kunci harta yang ditambahkan ke module.exportsobjek. Anda sebaliknya menggunakan nama lain, iaitu lifeOfPi.

Ini adalah perkara yang menarik untuk diperhatikan. Semasa anda mengeksport beberapa konstruksi pengkodan, anda boleh memberikan sebarang nama pada kunci semasa menambahkan harta yang ditambahkan ke module.exportsobjek. Tidak wajib menggunakan nama yang sama dengan nama yang anda gunakan semasa menentukan konstruk. Ini kerana anda boleh menggunakan pengecam yang sah sebagai kunci dalam objek JavaScript. Oleh itu, di sebelah kiri operator penugasan, anda boleh menggunakan pengecam yang sah, tetapi di sebelah kanan operator penugasan, anda perlu memberikan nilai yang ditakrifkan sebagai konstruk dalam ruang lingkup modul semasa (seperti yang anda telah menentukan pemboleh ubah dan fungsi dalam modul 'bulatan').

Perkara penting yang perlu diberi perhatian ialah semasa mengimport sesuatu dari modul lain dalam modul semasa, anda perlu menggunakan kunci yang sama dengan yang anda gunakan semasa mengeksportnya.

app.js

Kerana anda menggunakan kunci lifeOfPi, anda perlu menggunakan kunci yang sama untuk mengakses pemboleh ubah yang PIditentukan dalam circlemodul, seperti yang dilakukan dalam kod yang diberikan di atas.

Pengeluaran:

Area = 200.96, Circumference = 50.24pi = 3.14

Apa yang anda fikir akan berlaku jika anda menggunakan nama pembolehubah dan bukannya menggunakan kunci yang digunakan semasa mengeksport? Pendek kata, mari kita cuba mengakses PI(nama pemboleh ubah) dan bukannya lifeOfPi(kunci yang digunakan semasa mengeksport PI).

app.js

Pengeluaran:

Area = 200.96, Circumference = 50.24pi = undefined

Ini berlaku kerana module.exportsobjek tersebut tidak mengetahui pemboleh PIubahnya lagi. Ia hanya mengetahui tentang kunci yang ditambahkan kepadanya. Kerana kunci yang digunakan untuk mengeksport pemboleh ubah PIadalah lifeOfPi, yang terakhir hanya dapat digunakan untuk mengakses yang pertama.

TL; DR

  • Setiap fail di Node.js disebut sebagai modul .
  • Sebelum melaksanakan kod yang ditulis dalam modul, Node.js mengambil seluruh kod yang ditulis di dalam modul dan mengubahnya menjadi pembungkus fungsi, yang mempunyai sintaks berikut:
(function(exports, require, module, __filename, __dirname) { // entire module code lives in here});
  • Pembungkus fungsi memastikan bahawa semua kod yang ditulis di dalam modul adalah miliknya kecuali dinyatakan sebaliknya (dieksport). Parameter exports, require, module, __filename, dan __dirnamebertindak sebagai pembolehubah global kepada seluruh kod di dalam modul. Oleh kerana setiap modul mempunyai fungsi pembungkus sendiri, kod yang ditulis di dalam satu pembungkus fungsi menjadi lokal untuk pembungkus fungsi (modul baca) dan tidak dapat diakses di dalam pembungkus fungsi lain (modul baca).
  • modulekata kunci merujuk kepada objek yang mewakili modul semasa. The moduleobjek mempunyai kunci dinamakan exports. module.exportsadalah objek lain yang digunakan untuk menentukan apa yang dapat dieksport oleh modul dan dapat disediakan untuk modul lain. Ringkasnya, jika modul ingin mengeksport sesuatu, ia harus ditambahkan ke module.exportsobjek.
  • Nilai lalai module.exportsobjek adalah {}.
  • Terdapat tiga kaedah di mana anda boleh mengeksport sesuatu dari modul, atau menambahkan sesuatu ke module.exportsobjek:

    1. Tentukan semua konstruk terlebih dahulu dan kemudian gunakan beberapa module.exportspernyataan di mana setiap pernyataan digunakan untuk mengeksport konstruk.

    2. Tentukan semua konstruk terlebih dahulu dan kemudian gunakan satu module.exportspenyataan untuk mengeksport semua konstruk sekaligus mengikuti notasi literal objek.

    3. Tambahkan konstruk ke module.exportsobjek semasa menentukannya.

  • requirekata kunci merujuk kepada fungsi yang digunakan untuk mengimport semua pemboleh ubah dan fungsi yang dieksport menggunakan module.exportsobjek dari modul lain. Singkatnya, jika fail ingin mengimport sesuatu, ia mesti menyatakannya menggunakan sintaks berikut:
require('idOrPathOfModule');
  • Semasa mengeksport sesuatu dari modul, anda boleh menggunakan pengecam yang sah. Anda tidak perlu memberikan nama sebenar pemboleh ubah / fungsi sebagai kunci harta yang ditambahkan ke module.exportsobjek. Pastikan anda menggunakan kunci yang sama untuk mengakses sesuatu yang anda gunakan semasa mengeksportnya.