Bizning dasturimiz kattalashib borishi bilan biz uni âmodullarâ deb nomlangan bir nechta fayllarga ajratishni xohlaymiz. Modul odatda foydali funktsiyalar klassini yoki kutubxonasini oâz ichiga oladi.
Uzoq vaqt davomida JavaScript til darajasidagi modul sintaksisiz mavjud edi. Bu muammo emas edi, chunki dastlab skriptlar kichik va sodda edi. Shunday qilib, ehtiyoj yoâq edi.
Ammo oxir-oqibat skriptlar tobora murakkablashib bordi, shuning uchun hamjamiyat kodlarni modullarga joylashtirishning turli usullarini ixtiro qildi.
Masalan:
- AMD â dastlab kutubxona tomonidan amalga oshirilgan eng qadimgi modul tizimlaridan biri request.js.
- CommonJS â Node.js server uchun yaratilgan modul tizimi.
- UMD â yana bitta modul tizimi, universal sifatida tavsiya etilgan, AMD va CommonJS bilan mos keladi.
Endi bularning barchasi asta-sekin tarixning bir qismiga aylanadi, ammo biz ularni eski skriptlarda topishimiz mumkin. Til darajasidagi modul tizimi standartda 2015 yilda paydo boâlgan va oâsha paytdan boshlab asta-sekin rivojlanib borgan va hozirda barcha yirik brauzerlar va Node.js tomonidan qoâllab quvatlanadi.
Modul nima?
Modul â bu shunchaki fayl, bitta skript, shu kabi sodda.
export va import direktivalari modullar oârtasida funksiyalarni almashtirishga imkon beradi:
exportFayl tashqarisidan kirish mumkin boâlgan kalit soâzlar oâzgaruvchanlar va funktsiyalarni belgilaydi.importfunksiyalarni boshqa modullardan import qilishga imkon beradi.
Masalan, funktsiyani eksport qiladigan sayHi.js faylimiz boâlsa:
// ð sayHi.js
export function sayHi(user) {
alert(`Salom, ${user}!`);
}
â¦Keyin boshqa fayl uni import qilishi va ishlatishi mumkin:
// ð main.js
import {sayHi} from './sayHi.js';
alert(sayHi); // funktisya...
sayHi('John'); // Salom, John!
Ushbu qoâllanmada biz diqqatni tilning oâziga qaratamiz, ammo biz demo muhit sifatida brauzerdan foydalanamiz, shuning uchun brauzerda modullarning qanday ishlashini koârib chiqamiz.
Modullardan foydalanish uchun biz <script type="module"> atributini quyidagicha oârnatishimiz kerak:
export function sayHi(user) {
return `Salom, ${user}!`;
}<!DOCTYPE html>
<script type="module">
import { sayHi } from "./say.js";
document.body.innerHTML = sayHi("John");
</script>Brauzer avtomatik ravishda importni oladi va baholaydi, soângra skriptni bajaradi.
Asosiy modul xususiyatlari
âOddiyâ skriptlar bilan taqqoslaganda modullar bilan qanday farq bor?
Brauzerda ham, server tomonida ham JavaScript uchun amal qiladigan asosiy xususiyatlar mavjud.
Har doim âuse strictâ
Modullar doimo use strict dan foydalanadilar. Masalan, eâlon qilinmagan oâzgaruvchanga tayinlash xatoga yoâl qoâyadi.
<script type="module">
a = 5; // xato
</script>
Bu yerda biz uni brauzerda koârishimiz mumkin, ammo har qanday modul uchun ham xuddi shunday ishlaydi.
Maxsus oâzgaruvchan koâlam
Har bir modul oâzining yuqori darajadagi doirasiga ega. Boshqacha aytganda, moduldan yuqori darajadagi oâzgaruvchanlar va funktsiyalar boshqa skriptlarda koârinmaydi.
Quyidagi misolda ikkita skript import qilingan va hello.js user.js da eâlon qilingan user oâzgaruvchanidan foydalanishga harakat qiladi va bajarilmaydi:
alert(user); // no such variable (each module has independent variables)let user = "John";<!DOCTYPE html>
<script type="module" src="user.js"></script>
<script type="module" src="hello.js"></script>Modullar tashqaridan kirishni xohlagan narsalarini export qilishlari va kerakli narsalarini import qilishlari kutilmoqda.
Shuning uchun biz user.js ni index.html oârniga toâgâridan-toâgâri hello.js ga import qilishimiz kerak.
Bu toâgâri variant:
import { user } from "./user.js";
document.body.innerHTML = user; // Johnexport let user = "John";<!DOCTYPE html>
<script type="module" src="hello.js"></script>Brauzerda har bir <script type="module"> uchun mustaqil yuqori darajadagi koâlam mavjud:
<script type="module">
// O'zgaruvchan faqat ushbu modul skriptida ko'rinadi
let user = "John";
</script>
<script type="module">
alert(user); // Error: user is not defined
</script>
Agar biz chindan ham âglobalâ brauzer ichida oâzgaruvchanni yaratishimiz kerak boâlsa, uni window ga aniq belgilashimiz va window.user sifatida kirishimiz mumkin. Ammo bu yaxshi sababni talab qiladigan istisno.
Import qilinganida modul kodi faqat birinchi marta baholanadi
Agar bir xil modul boshqa bir qancha joylarga import qilingan boâlsa, uning kodi faqat birinchi marta bajariladi, keyin eksport barcha importerlarga beriladi.
Bu muhim oqibatlarga olib keladi. Keling, buni misollarda koârib chiqaylik.
Birinchidan, agar modul kodini bajarish xabarni koârsatish kabi nojoâya taâsirlarni keltirib chiqarsa, uni bir necha marta import qilish uni faqat bir marta bajaradi, birinchi marta:
// ð alert.js
alert("Modul baholandi!");
// Xuddi shu modulni turli xil fayllardan import qiling
// ð 1.js
import `./alert.js`; // Modul baholandi!
// ð 2.js
import `./alert.js`; // (hech narsa)
Amalda, yuqori darajadagi modul kodi asosan ishga tushirish uchun ishlatiladi. Biz maâlumotlar tuzilmalarini yaratamiz, ularni oldindan toâldiramiz va agar biror narsa qayta ishlatilishini istasak â uni eksport qilamiz.
Endi yanada rivojlangan misol.
Aytaylik, modul obyektni eksport qiladi:
// ð admin.js
export let admin = {
name: "John"
};
Agar ushbu modul bir nechta fayllardan import qilingan boâlsa, modul faqat birinchi marta baholanadi, admin obyekti yaratiladi va keyinchalik barcha boshqa import qiluvchilarga beriladi.
Barcha importchilar aynan bitta admin obyektini oladi:
// ð 1.js
import {admin} from './admin.js';
admin.name = "Pete";
// ð 2.js
import {admin} from './admin.js';
alert(admin.name); // Pete
// 1.js va 2.js ikkalasi ham bitta obyektni import qildilar
// 1.js-da kiritilgan o'zgarishlar 2.js-da ko'rinadi
Shunday qilib, yana takrorlaymiz â modul faqat bir marta bajariladi. Eksportlar yaratiladi, soângra ular importchilar oârtasida taqsimlanadi, shuning uchun agar biror narsa admin obyektini oâzgartirsa, boshqa modullar buni koârishadi.
Bunday xatti-harakatlar konfiguratsiyani talab qiladigan modullar uchun juda yaxshi. Birinchi importda kerakli xususiyatlarni oârnatishimiz mumkin, keyin esa keyingi importda u tayyor boâladi.
Masalan, admin.js moduli maâlum funktsiyalarni taqdim etishi mumkin, ammo hisobga olish maâlumotlari admin obyektiga tashqaridan kirishini kutadi:
// ð admin.js
export let config = { };
export function sayHi() {
alert(`Xizmat qilishga tayyor, ${admin.name}!`);
}
Endi dasturimizning birinchi skripti boâlgan init.js da biz admin.name ni oârnatdik. Keyin hamma buni koâradi, shu jumladan admin.js ning oâzi tomonidan qilingan chaqiruvlarni:
// ð init.js
import {config} from './admin.js';
config.user = "Pete";
â¦Now the module admin.js is configured.
Further importers can call it, and it correctly shows the current user:
// ð another.js
import {sayHi} from './admin.js';
sayHi(); // Xizmat qilishga tayyor, Pete!
import.meta
import.meta obyekti joriy modul haqidagi maâlumotlarni oâz ichiga oladi.
Uning tarkibi atrof-muhitga bogâliq. Brauzerda u skriptning URL manzilini yoki HTML ichida mavjud veb-sahifaning URL-ini oâz ichiga oladi:
<script type="module">
alert(import.meta.url); // skript url (ichki skript uchun HTML sahifasining url)
</script>
Yuqori darajadagi âthisâ aniqlanmagan
Bu kichik xususiyatning bir turi, ammo toâliqligi uchun buni eslatib oâtishimiz kerak.
Modulda yuqori darajadagi this, modul boâlmagan skriptlardagi global obyektdan farqli oâlaroq, u aniqlanmagan:
<script>
alert(this); // window
</script>
<script type="module">
alert(this); // undefined
</script>
Brauzerga xos xususiyatlar
Brauzerga xos boâlgan type="module" skriptlarining bir nechta farqlari mavjud.
Agar siz birinchi marta oâqiyotgan boâlsangiz yoki JavaScript-ni brauzerda ishlatmasangiz, ularni hozircha oâtkazib yuborishingiz mumkin.
Modul skriptlari keyinga qoldiriladi
Modul skriptlari har doim keyinga qoldiriladi, tashqi va ichki satrlar uchun defer atributi (Skriptlar: async, defer bobda tasvirlangan) bir xil taâsirga ega.
Boshqa soâzlar bilan aytganda:
- tashqi modul skriptlari
<script type="module" src="...">HTML ishlov berishni bloklamang. - modul skriptlari HTML hujjat toâliq tayyor boâlguncha kutib turadi.
- nisbiy tartib saqlanib qoladi: hujjatda birinchi boâlib turgan skriptlar birinchi bajariladi.
Yon effekt sifatida modul skriptlari doimo HTML ostidagi elementlarni koâradi.
Masalan:
<script type="module">
alert(typeof button); // object: skript quyidagi tugmani "ko'rishi" mumkin
// modullar keyinga qoldirilishi uchun, skript butun sahifa yuklangandan so'ng ishlaydi
</script>
Compare to regular script below:
<script>
alert(typeof button); // button is undefined, the script can't see elements below
// muntazam skriptlar darhol ishlaydi, sahifaning qolgan qismi qayta ishlanmasdan oldin
</script>
<button id="button">Button</button>
Iltimos, diqqat qiling: ikkinchi skript aslida birinchisidan oldin ishlaydi! Shunday qilib, avval undefined ni, keyin esa object koâramiz.
Buning sababi, modullarning keyinga qoldirilishi, shuning uchun hujjatning ishlashini kuting. Oddiy skriptlar darhol ishlaydi, shuning uchun birinchi navbatda uning chiqishini koârdik.
Modullardan foydalanganda HTML-hujjat JavaScript dasturi tayyor boâlguncha paydo boâlishi mumkinligini bilishimiz kerak. Baâzi funktsiyalar hali ishlamasligi mumkin. Biz shaffof qoplamalar yoki âyuklash koârsatkichlariâ ni qoâyishimiz kerak, yoki boshqa sabablarga koâra tashrif buyuruvchilar chalkashib ketmasligini taâminlashimiz kerak.
Async ichki skriptlarda ishlaydi
Async atributiga <script async type="module"> ichki va tashqi skriptlarda ruxsat beriladi. Async skriptlari import qilingan modullarni qayta ishlashda darhol ishlaydi, boshqa skriptlardan yoki HTML-hujjatdan mustaqil ravishda.
Masalan, quyidagi skriptda async mavjud, shuning uchun u hech kimni kutmaydi.
U importni amalga oshiradi (./analytics.js olib keladi) va tayyor boâlganda ishlaydi, hattoki HTML hujjati hali tugallanmagan boâlsa yoki boshqa skriptlar hali kutilayotgan boâlsa ham.
Bu hisoblagichlar, eâlonlar, hujjatlar darajasidagi tadbirlarni tinglovchilar kabi hech narsaga bogâliq boâlmagan funksionallik uchun yaxshi.
<!-- barcha bog'liqliklar olinadi (analytics.js) va skript ishlaydi -->
<!-- hujjat yoki boshqa <script> teglarini kutmaydi -->
<script async type="module">
import {counter} from './analytics.js';
counter.count();
</script>
Tashqi skriptlar
Tashqi modul skriptlarining ikkita sezilarli farqlari mavjud:
-
Xuddi shu
srctashqi skriptlar faqat bir marta ishlaydi:<!-- my.js skripti faqat bir marta olinadi va bajariladi --> <script type="module" src="my.js"></script> <script type="module" src="my.js"></script> -
Boshqa domendan olinadigan tashqi skriptlar CORS sarlavhalarini talab qiladi. Boshqacha qilib aytadigan boâlsak, agar boshqa domendan modul skripti olinsa, masofaviy server
Access-Control-Allow-Origin: *sarlavhasini taqdim qilishi kerak (*oârniga domenni olib kelishi mumkin). .<!-- another-site.com veb-saytini etkazib berishi kerak Access-Control-Allow-Origin --> <!-- aks holda, skript bajarilmaydi --> <script type="module" src="http://another-site.com/their.js"></script>Bu sukut boâyicha xavfsizlikni yaxshiroq taâminlaydi.
âYalangâochâ modullarga ruxsat berilmaydi
Brauzerda skriptlarda (HTML-da emas) import nisbiy yoki mutlaq URLni olishi kerak. Yoâlsiz âyalangâochâ modullarga ruxsat berilmaydi.
Masalan, ushbu import yaroqsiz:
import {sayHi} from 'sayHi'; // Xato, "yalang'och" modul
// './sayHi.js' bo'lishi kerak
Node.js yoki tugâun vositalari kabi baâzi bir muhitlar yalangâoch modullarga ruxsat beradi, chunki ularda modullarni topish usullari va ularni aniq sozlash uchun ilgaklar mavjud. Ammo brauzerlar hali yalangâoch modullarni qoâllab-quvvatlamaydi.
Moslik, ânomoduleâ
Eski brauzerlar type="module" ni tushunmaydilar. Nomaâlum turdagi skriptlar shunchaki eâtiborsiz qoldiriladi. Ular uchun nomodule atributidan foydalanib, qaytarib berishni taâminlash mumkin:
<script type="module">
alert("Zamonaviy brauzerlarda ishlaydi");
</script>
<script nomodule>
alert("Zamonaviy brauzerlar type=module va nomodule ikkalasini ham bilishadi, shuning uchun buni o'tkazib yuboring")
alert("Eski brauzerlar type=module noma'lum bo'lgan skriptni e'tiborsiz qoldiradi, lekin buni bajaradi.");
</script>
Agar biz toâplam vositalaridan foydalansak, unda modullar birlashtirilganligi sababli, ularning import/export soâzlari maxsus paketli chaqiruvlar bilan almashtiriladi, shuning uchun hosil boâladigan qurilish type="module" ni talab qilmaydi va biz uni odatiy skriptga keltira olamiz:
<!-- Bundle.js-ni Webpack kabi vositadan olganmiz deb taxmin qilamiz-->
<script src="bundle.js"></script>
Oârnatish vositalari
Haqiqiy hayotda brauzer modullari kamdan-kam hollarda âxomâ shaklida qoâllaniladi. Odatda, biz ularni Webpack kabi maxsus vosita bilan birlashtiramiz va ishlab chiqarish serveriga joylashtiramiz.
Paketlardan foydalanishning afzalliklaridan biri bu CSS/HTML modullari singari yalangâoch modullarga va boshqalarga imkon beradigan modullarning yechimi ustidan koâproq nazorat qilishdir.
Qurilish vositalari quyidagilarni bajaradi:
- HTML-da
<script type="module">ga joylashtirilishi kerak boâlgan âasosiyâ modulni oladi. - Uning bogâliqligini tahlil qiladi: import va undan keyin import importi va boshqalar.
- Mahalliy
importchaqiruvlarini toâplami funktsiyalari bilan almashtirib, barcha modullar (yoki sozlanishi mumkin boâlgan bir nechta fayllar) bilan bitta fayl yaratadi. HTML/CSS modullari kabi âmaxsusâ modul turlari ham qoâllab-quvvatlanadi. - Jarayonda boshqa transformatsiyalar va optimallashtirishlar qoâllanilishi mumkin:
- Qabul qilinmaydigan kod olib tashlandi.
- Foydalanilmagan eksport olib tashlandi (âtree-shakingâ).
consolevadebuggerkabi ishlab chiqishga oid soâzlar olib tashlandi.- Zamonaviy, qon ketishining cheklangan JavaScript-ni sintaksisini Babel yordamida oâxshash funktsional imkoniyatga ega boâlgan eskisiga aylantirish mumkin.
- Olingan fayl kichraytiriladi (boâshliqlar olib tashlanadi, oâzgaruvchanlar qisqa nom bilan almashtiriladi va hokazo).
Yaâni, mahalliy modullardan ham foydalanish mumkin. Shuning uchun biz bu erda Webpack-dan foydalanmaymiz: uni keyinroq sozlashingiz mumkin.
Xulosa
Xulosa qilib aytganda, asosiy tushunchalar:
- Modul â bu fayl.
import/exportishini bajarish uchun brauzerlarda<script type="module">boâlishi kerak, bu bir nechta farqlarni anglatadi:- Sukut boâyicha keyinga qoldirigan(deferred).
- Async ichki skriptlarda ishlaydi.
- Tashqi skriptlarga CORS sarlavhalari kerak.
- Ikki nusxadagi tashqi skriptlarga eâtibor berilmaydi.
- Modullar oâzlarining mahalliy darajadagi yuqori darajalariga va
import/exportorqali almashinuv funktsiyalariga ega. - Modullar har doim
use strictdan foydalanadi. - Modul kodi faqat bir marta bajariladi. Eksport bir marta tuziladi va importchilar oârtasida taqsimlanadi.
Umuman olganda, modullardan foydalanganda har bir modul funksionallikni amalga oshiradi va uni eksport qiladi. Keyin uni kerakli joyga toâgâridan-toâgâri import qilish uchun import dan foydalanamiz. Brauzer skriptlarni avtomatik ravishda yuklaydi va baholaydi.
Ishlab chiqarishda odamlar koâpincha Webpack kabi toâplamlardan ishlash va boshqa sabablarga koâra modullarni birlashtirish uchun foydalanadilar.
Keyingi bobda biz modullarning koâproq namunalarini va qanday qilib eksport/import qilish mumkinligini koârib chiqamiz.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâ¦)