Modullar, kirish
Loyiha o'sib borgan sari, kodni bir nechta fayllarga โ modullarga โ ajratish zarurati tug'iladi. Modul odatda funksiya yoki funksiyalar kutubxonasini o'z ichiga oladi. Ushbu darsda modul nima ekanligini, u qanday ishlashini va uning o'ziga xos xususiyatlarini chuqur o'rganamiz.
Modul nima?
Modul โ bu shunchaki bitta fayl. Bitta skript โ bu bitta modul. Oddiy va aniq: JavaScript'da har bir fayl alohida modul hisoblanadi.
Modullar bir-birini import va export kalit so'zlari yordamida chaqira oladi va o'zaro funksionallik almashadi โ biri boshqasidan funksiyalarni chaqiradi:
exportkalit so'zi joriy moduldan tashqariga chiqarilishi kerak bo'lgan o'zgaruvchi va funksiyalarni belgilaydi ("eksport qiladi");importkalit so'zi boshqa moduldan funksionallikni olib kirishga ("import qilishga") imkon beradi.
Masalan, bizda sayHi funksiyasini eksport qiladigan fayl bo'lsa:
// ๐ sayHi.js
export function sayHi(user) {
alert(`Salom, ${user}!`);
}
Boshqa faylda uni import qilib, ishlatamiz:
// ๐ main.js
import { sayHi } from './sayHi.js';
alert(sayHi); // function...
sayHi('Ali'); // Salom, Ali!
Bu yerda import { sayHi } from './sayHi.js' direktivasi sayHi.js fayliga nisbatan yo'l bo'yicha modulni yuklaydi va eksport qilingan sayHi funksiyasini joriy modulda foydalanish uchun mavjud qiladi.
'./sayHi.js'. ./ โ joriy papkani bildiradi. Ba'zi build tizimlari kengaytmasiz ('./sayHi') yozishga ruxsat bersa-da, sof brauzer modullarida .js kengaytmasi zarur.Brauzerda modullar: script type=module
Brauzer modullarni oddiy skriptlardan farqli ravishda yuklaydi. Modul ishlatilishi uchun HTML'da <script> tegiga maxsus atribut qo'shiladi: type="module".
<!DOCTYPE html>
<script type="module">
import { sayHi } from './sayHi.js';
document.body.innerHTML = sayHi('Vali');
</script>
Faqat type="module" bilan belgilangan skript ichida import ishlaydi. Oddiy <script>da import yozsangiz, xatolik yuz beradi.
file://) orqali emas. Ya'ni faylni to'g'ridan-to'g'ri brauzerda ochsangiz, import/export ishlamaydi. Lokal veb-server (masalan, live server yoki VS Code kengaytmasi) ishga tushiring..mjs kengaytmasiga ega bo'lsa yoki package.jsonda "type": "module" ko'rsatilgan bo'lsa, ES modullari ishlaydi. Ushbu kurs sahifasidagi interaktiv maydonchada import/export ishlamaydi โ shu sabab bu darslarda ular faqat statik misol sifatida keltiriladi.Modulning o'ziga xos xususiyatlari
Modullar oddiy skriptlardan bir necha muhim jihatlari bilan farq qiladi. Ularni birma-bir ko'rib chiqamiz.
1. Har doim "use strict"
Modullar doim qat'iy rejimda (strict mode) ishlaydi. Buni alohida yozish shart emas โ u avtomatik yoqilgan. Masalan, e'lon qilinmagan o'zgaruvchiga qiymat berish xatolik beradi:
<script type="module">
a = 5; // ReferenceError: a is not defined
</script>
2. Har bir modulning o'z ko'lami (scope) bor
Har bir modulning o'z yuqori darajali (top-level) ko'lami bo'ladi. Bir modulning yuqori darajali o'zgaruvchi va funksiyalari boshqa modullarda ko'rinmaydi.
// ๐ user.js
let user = 'John';
// ๐ hello.js
alert(user); // xatolik: user is not defined
Modullar tashqariga chiqarmoqchi bo'lgan narsalarni export qilishi, foydalanmoqchi bo'lganlarini esa import qilishi kerak. Ya'ni har bir modul o'z o'zgaruvchilarini yashiradi (encapsulation).
Brauzerda ham har bir <script type="module">ning alohida yuqori darajali ko'lami bo'ladi:
<script type="module">
let user = 'John';
</script>
<script type="module">
alert(user); // Error: user is not defined
</script>
window obyektiga tayinlashingiz kerak: window.user = user. Lekin bu kamdan-kam holatda tavsiya etiladi.3. Modul kodi faqat bir marta baholanadi
Agar bir modul bir necha joyda import qilinsa, uning kodi faqat birinchi importda bir marta ishga tushiriladi. Natija esa barcha importer'larga uzatiladi. Bu muhim oqibatlarga ega.
Bir marta baholanish yon ta'sirlar (side-effects) uchun ahamiyatli. Masalan, modul quyidagicha xabar chiqarsin:
// ๐ alert.js
alert('Modul baholandi!');
// ๐ 1.js
import './alert.js'; // Modul baholandi!
// ๐ 2.js
import './alert.js'; // (hech narsa ko'rsatilmaydi)
Ikkinchi import hech qanday narsa ko'rsatmaydi, chunki modul allaqachon baholangan.
Amaliyotda bu shuni anglatadiki: modulning yuqori darajali kodi odatda ishga tayyorlash (initialization), ichki ma'lumot tuzilmalarini yaratish uchun ishlatiladi. Agar biror obyektni eksport qilsak, u barcha importer'lar uchun bir xil (yagona nusxa) bo'ladi:
// ๐ admin.js
export let admin = {
name: 'John'
};
// ๐ 1.js
import { admin } from './admin.js';
admin.name = 'Pete';
// ๐ 2.js
import { admin } from './admin.js';
alert(admin.name); // Pete
// Ikkala fayl ham bir xil admin obyektiga murojaat qiladi.
// 1.js dagi o'zgarish 2.js da ham ko'rinadi.
4. import.meta
import.meta obyekti joriy modul haqidagi ma'lumotni saqlaydi. Uning tarkibi muhitga bog'liq. Brauzerda u odatda skriptning URL manzilini o'z ichiga oladi:
<script type="module">
alert(import.meta.url); // skript fayl URL manzili
</script>
5. "this" โ undefined
Modulning yuqori darajasida this qiymati undefined bo'ladi (oddiy skriptdagi window emas). Buni qat'iy rejim bilan solishtiring:
<script>
alert(this); // window
</script>
<script type="module">
alert(this); // undefined
</script>
Brauzerga xos xususiyatlar
Brauzer muhitida modul skriptlari yana bir necha o'ziga xoslikka ega.
Modul skriptlari kechiktirilgan (deferred)
Modul skriptlari har doim deferred โ huddi defer atributi qo'yilgandek ishlaydi. Bu tashqi (src bilan) va ichki (inline) modullar uchun ham amal qiladi. Bundan kelib chiqadigan xususiyatlar:
- Tashqi modul skriptini yuklash HTML'ni qayta ishlashni bloklamaydi โ brauzer boshqa resurslarni parallel yuklaydi;
- Modul skriptlari HTML hujjat to'liq tayyor bo'lgunga qadar kutadi (hatto kichik bo'lsa ham) va faqat undan keyin ishga tushadi;
- Skriptlarning nisbiy tartibi saqlanadi: hujjatda oldin turgan skript avval bajariladi.
<script type="module">
// button hujjatda pastroqda bo'lsa ham ko'rinadi,
// chunki modul deferred โ u HTML tayyor bo'lgach ishlaydi
alert(typeof button); // object
</script>
<button id="button">Button</button>
Solishtiring: oddiy (non-module) skript darhol ishga tushardi va typeof button undefined bo'lardi, chunki brauzer hali buttonni ko'rmagan bo'lardi.
Async atributi inline skriptlarda ishlaydi
Oddiy skriptlarda async atributi faqat tashqi skriptlar uchun ishlaydi. Modullarda esa u inline skriptlarda ham ishlaydi. async bilan skript boshqa skriptlar va HTML'ni kutmasdan, tayyor bo'lishi bilanoq ishga tushadi. Bu import'lar yuklangan analitika, reklama kabi mustaqil funksionallik uchun qulay.
<script async type="module">
import { counter } from './analytics.js';
counter.count();
</script>
Tashqi skriptlar
type="module" bilan tashqi skriptlar ikki jihatda farq qiladi:
- Bir xil
srcga ega tashqi modullar faqat bir marta bajariladi; - Boshqa manbadan (origin) yuklangan tashqi skript CORS sarlavhalarini talab qiladi โ uzoq server
Access-Control-Allow-Originsarlavhasi bilan ruxsat berishi kerak.
<!-- another-site.com CORS ruxsatini berishi kerak,
aks holda skript ishlamaydi -->
<script type="module" src="http://another-site.com/module.js"></script>
"Yalang'och" (bare) modullarga ruxsat yo'q
Brauzerda import yo'li nisbiy yoki mutlaq bo'lishi kerak. Yo'lsiz, faqat nom bilan yozilgan ("bare") modullarga ruxsat yo'q:
import { sayHi } from 'sayHi'; // Xatolik! "bare" modul
// yo'l bo'lishi kerak, masalan './sayHi.js'
node_modulesdan). Lekin sof brauzer bunday qilmaydi.Xulosa
- Modul โ bu bitta fayl. Modullar
import/exportorqali funksionallik almashadi; - Brauzerda modullar
<script type="module">orqali yuklanadi; - Modullar doim qat'iy rejimda ishlaydi;
- Har bir modulning o'z ko'lami bor โ global o'zgaruvchilarni bir-biriga "chalishtirmaydi";
- Modul kodi ko'p marta import qilinsa ham faqat bir marta baholanadi (yagona nusxa);
- Yuqori darajadagi
thisโundefined,import.metamodul haqida ma'lumot beradi; - Brauzerda modul skriptlari doim deferred,
asyncesa inline skriptlarda ishlaydi; - Yo'lsiz "bare" modullar sof brauzerda ishlamaydi.