Node.js modul tizimi: CommonJS va ES modul
Butun dasturni bitta app.js ichiga yozsangiz, fayl bir necha yuz
qatorga yetadi va kerakli joyni topish qiyinlashadi. Yechim — kodni
mavzuga qarab bo’lish. npm darsida require
va module.exports ni qisqa ko’rgan edingiz. Endi ularni chuqurroq
o’rganamiz: eksportning turli shakllari, keshi va tuzoqlari.
Modul nima
Muhim jihat: modul ichidagi o’zgaruvchi tashqariga sizib chiqmaydi. Ikki faylda bir xil nom ishlatsangiz ham to’qnashmaydi.
Birinchi modul
Kalkulyator moduli yozamiz. math.js fayli:
// Bu o'zgaruvchi faqat shu fayl ichida ko'rinadi
const PRECISION = 2;
function add(a, b) {
return a + b;
}
function divide(a, b) {
if (b === 0) {
return null;
}
return Number((a / b).toFixed(PRECISION));
}
// Tashqariga faqat shu ikki funksiyani beramiz
module.exports = { add, divide };
Endi app.js da ishlatamiz:
const math = require("./math");
console.log("Yig'indi:", math.add(10, 5));
console.log("Bo'linma:", math.divide(10, 3));
console.log("Nolga bo'lish:", math.divide(10, 0));
node app.js
Yig'indi: 15
Bo'linma: 3.33
Nolga bo'lish: null
PRECISION eksport qilinmagani uchun app.js uni ko’rmaydi. Modul
ichidagi tafsilot ichida qoladi.
module.exports ning uch shakli
Eksportni qanday yozish kerakligi nimani berayotganingizga bog’liq.
1. Obyekt — bir nechta narsa berilganda (eng ko’p ishlatiladigani):
// text-tools.js
function toUpper(text) {
return text.toUpperCase();
}
function countWords(text) {
return text.trim().split(/\s+/).length;
}
module.exports = { toUpper, countWords };
Olib kirishda destrukturizatsiya qulay:
const { toUpper, countWords } = require("./text-tools");
console.log(toUpper("salom dunyo"));
console.log(countWords("bir ikki uch"));
SALOM DUNYO
3
2. Bitta funksiya — modul bitta ish qilsa:
// greet.js
module.exports = function greet(name) {
return `Salom, ${name}!`;
};
const greet = require("./greet");
console.log(greet("Aziz"));
Salom, Aziz!
Bu yerda nom siz tanlagan bo’ladi: require qaytargan qiymatni istagan
nomga yozasiz.
3. Klass — obyekt yaratish kerak bo’lsa:
// Counter.js
class Counter {
constructor(startValue = 0) {
this.value = startValue;
}
increase() {
this.value += 1;
return this.value;
}
}
module.exports = Counter;
const Counter = require("./Counter");
const visits = new Counter(10);
console.log(visits.increase());
console.log(visits.increase());
11
12
Klasslar darsidagi sintaksis Node.js’da xuddi shunday ishlaydi.
exports va module.exports farqi
Ikkala nomni ham kodda uchratasiz. Ular boshqa-boshqa narsa emas: fayl
boshida exports — module.exports ga ishora qiluvchi qisqartma.
Qo’shimcha qilish ikkalasida ham ishlaydi:
// tools.js
exports.sum = (a, b) => a + b;
exports.multiply = (a, b) => a * b;
const tools = require("./tools");
console.log(tools.sum(3, 4));
console.log(tools.multiply(3, 4));
7
12
Muammo exports ga yangi qiymat berilganda boshlanadi:
// broken.js — bu ishlamaydi
exports = { sum: (a, b) => a + b };
const broken = require("./broken");
console.log(broken);
console.log(typeof broken.sum);
{}
undefined
Bo’sh obyekt qaytdi. Sabab: exports ga yangi obyekt yozilganda u
module.exports bilan aloqasini uzadi, require esa har doim
module.exports ni qaytaradi.
| Yozuv | Ishlaydimi | Izoh |
|---|---|---|
module.exports = { add } |
Ha | To’liq almashtirish |
exports.add = add |
Ha | Mavjud obyektga qo’shish |
exports = { add } |
Yo’q | Aloqa uziladi |
require keshi
Bitta modulni ikki marta chaqirsangiz, fayl bir marta bajariladi. Natija saqlanadi va ikkinchi safar tayyor holda beriladi.
config.js yarating:
console.log("config.js bajarildi");
module.exports = { appName: "Test dastur" };
Endi uni ikki marta chaqiramiz:
const firstConfig = require("./config");
const secondConfig = require("./config");
console.log(firstConfig.appName);
console.log("Bir xil obyektmi:", firstConfig === secondConfig);
config.js bajarildi
Test dastur
Bir xil obyektmi: true
config.js bajarildi matni bir marta chiqdi, garchi require ikki
marta yozilgan bo’lsa ham.
Buning amaliy foydasi bor: ma’lumotlar bazasiga ulanish yoki sozlamalar moduli necha marta chaqirilsa ham bitta nusxada qoladi.
Doiraviy bog’liqlik
Ikki modul bir-birini chaqirsa, holat chalkashadi.
// first.js
const second = require("./second");
console.log("first.js ichida second:", second);
module.exports = { name: "first" };
// second.js
const first = require("./first");
console.log("second.js ichida first:", first);
module.exports = { name: "second" };
node first.js
second.js ichida first: {}
first.js ichida second: { name: 'second' }
Birinchi qatorga qarang: second.js first ni bo’sh obyekt sifatida
ko’rdi. Sabab: first.js hali eksportini tugatmagan paytda second.js
uni so’radi.
Node.js bunga qo’shimcha ogohlantirish ham chiqaradi:
Warning: Accessing non-existent property 'constructor' of module exports
inside circular dependency
Bu xabar aynan shu muammoni ko’rsatadi: modul hali to’liq tayyor emas.
__dirname va __filename
Modul ichida ikki maxsus o’zgaruvchi mavjud:
// paths.js
console.log("Papka:", __dirname);
console.log("Fayl:", __filename);
Papka: D:\node-start
Fayl: D:\node-start\paths.js
| O’zgaruvchi | Nimani beradi |
|---|---|
__dirname |
Fayl turgan papkaning to’liq yo’li |
__filename |
Faylning o’zining to’liq yo’li |
Ular fayl bilan ishlashda kerak bo’ladi — path moduli darsida nima uchun aynan shu o’zgaruvchi ishlatilishini ko’rasiz.
“type”: “module” ni yoqsak nima o’zgaradi
package.json ga bitta qator qo’shilganda tizim to’liq almashadi:
{
"name": "node-start",
"version": "1.0.0",
"type": "module"
}
Shundan keyin require o’rniga import yoziladi:
// math.js
export function add(a, b) {
return a + b;
}
export function divide(a, b) {
if (b === 0) {
return null;
}
return Number((a / b).toFixed(2));
}
// app.js
import { add, divide } from "./math.js";
console.log(add(10, 5));
console.log(divide(10, 3));
15
3.33
Uch narsa o’zgaradi:
- Fayl kengaytmasi majburiy:
"./math.js","./math"emas; __dirnameva__filenameyo’qoladi;requireishlamaydi.
JavaScript modullari darsidagi import sintaksisi
bilan bu bir xil tizim. Farq faqat Node.js’ning uni yoqish usulida.
Amaliy mashq
node-start papkasida bajaring:
math.jsmoduli yaratib,addvadividefunksiyalarini eksport qiling,app.jsda chaqiring;math.jsga eksport qilinmagan o’zgaruvchi qo’shing va uniapp.jsdan o’qishga urinib ko’ring —undefinedchiqadi;Counterklassini alohida faylga chiqarib,app.jsda ikkita alohida hisoblagich yarating;exports = { ... }shaklini ataylab yozib,requirebo’sh obyekt qaytarishini o’z ko’zingiz bilan ko’ring;- Ichida
console.logbor modul yozib, uni bir faylda ikki martarequireqiling — xabar bir marta chiqadi; package.jsonga"type": "module"qo’shib,requireqanday xato berishini o’qing, keyin qatorni olib tashlang.
4-qadam eng muhimi: exports bilan bog’liq bu tuzoq Node.js’da eng ko’p
vaqt yo’qotadigan chalkashliklardan biri.
Qisqacha xulosa
- Har
.jsfayl alohida modul: ichidagi o’zgaruvchi tashqariga chiqmaydi. module.exportsobyekt, funksiya yoki klass qaytarishi mumkin.exports.name = ...qo’shadi,exports = ...esa aloqani uzadi — to’liq almashtirishdamodule.exportsyoziladi.requirenatijani keshlaydi: fayl necha marta chaqirilsa ham bir marta bajariladi.- Doiraviy bog’liqlikda modul yarim tayyor holatda ko’rinadi — umumiy qismni uchinchi faylga ajrating.
__dirnamefayl turgan papkani beradi, lekin ES modulda mavjud emas."type": "module"butun loyihaniimporttizimiga o’tkazadi.
Keyingi darsda fs moduli — diskdagi fayllarni o’qish va yozish.