Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. Leksik muhit
- 2.1 Ikki qism
- 2.2 O'xshatish: manzil
- 3. Scope zanjiri
- 3.1 Qidiruv qoidasi
- 3.2 Qadamma-qadam
- 3.3 Birinchi topilgani yutadi
- 3.4 O'zgartirish ham zanjir bo'ylab
- 4. Leksik scope: "qayerda yozilgan" muhim
- 4.1 Tashqi havola qachon belgilanadi
- 4.2 Taqqoslash uchun: dinamik scope
- 4.3 Callback'lar ham yozilgan joyini ko'radi
- 4.4 Zanjir kod yozilganda ma'lum
- 5. DevTools'da scope zanjiri
- 6. Ko'p uchraydigan xatolar
- 6.1 Chaqirgan joyning o'zgaruvchisini kutish
- 6.2 Imlo xatosi — "aniqlanmagan"
- 6.3 Ichki nom tashqisini yashirib qo'yadi
- 6.4 Qo'shni funksiyaning o'zgaruvchisi
- 7. Mashqlar
- 1-mashq (oson): Qaysi qiymat?
- 2-mashq (o'rta): Zanjirni yozing
- 3-mashq (qiyin): Yashirin bog'liqlikni tuzating
- 4-mashq: Vazifalar qadami — fokusla ning zanjiri
- 8. Real ishda
- Xulosa
- Manbalar
JavaScript leksik scope va scope zanjiri: o'zgaruvchi qayerdan topiladi
Qisqacha: JavaScript'da o'zgaruvchi kod qayerda yozilganiga qarab qidiriladi, qayerdan chaqirilganiga qarab emas — bu leksik (statik) scope. Har blok, funksiya va fayl o'z leksik muhitiga ega: unda o'z nomlari va tashqi muhitga havola bor. Nom topilmasa, JavaScript shu havolalar bo'ylab ichkaridan tashqariga yuradi — bu scope zanjiri. Zanjir oxirigacha topilmasa —
ReferenceError.
Bu darsda
- Leksik muhit nimadan iboratini tushuntira olasiz.
- Scope zanjiri bo'ylab nom qanday qidirilishini qadamma-qadam ko'rsata olasiz.
- Funksiya nega chaqirgan joyining emas, yozilgan joyining o'zgaruvchilarini ko'rishini tushuntirasiz.
- Leksik va dinamik scope farqini misol bilan ayta olasiz.
vazifalar.jsdagi ichma-ich funksiyaning scope zanjirini chizasiz.
Oldin bilishingiz kerak: Scope asoslari: global, funksiya va blok, Execution context va call stack.
1. Nega bu kerak?
Kodni ishga tushirmasdan javob bering — oxirgi qator nima chiqaradi?
const choyxona = "Bahor";
function nomniAyt() {
console.log(choyxona);
}
function boshqaKafe() {
const choyxona = "Lola";
nomniAyt();
}
boshqaKafe(); // BahorKo'pchilik "Lola" deydi. Mantiq oddiyga o'xshaydi: nomniAyt ni boshqaKafe chaqirdi, u yerda choyxona — "Lola". Lekin javob — "Bahor".
Scope asoslari darsida qoidani ko'rgan edik: ichkaridagi kod tashqaridagini ko'radi. Lekin "ichkari" va "tashqari" nimaga qarab aniqlanadi — kod matnigami yoki chaqiruvlar tartibigami? Bu dars shu savolga javob beradi. Javobni bilmasangiz, ertaga vazifalar ni modullarga bo'lganda va callback'larni boshqa funksiyalarga berganda "o'zgaruvchi nega ko'rinmayapti?" degan xatolarga ko'p uchraysiz.
O'tgan darsda execution context uch qismdan iborat dedik: o'zgaruvchilar, tashqi havola va this. Bugun ikkinchisini ochamiz.
2. Leksik muhit
2.1 Ikki qism
Leksik muhit (lexical environment) — nomlar va ularning qiymatlari yozilgan jadval, qo'shimcha ravishda tashqi muhitga havola bilan. "Leksik" — "matnga oid": u kod matnidagi joylashuvga qarab quriladi.
Har leksik muhitda ikki narsa bor:
| Qism | Nima | Misol |
|---|---|---|
| Yozuvlar jadvali | Shu hududda e'lon qilingan nomlar | taom: "osh", manzil: "Chilonzor" |
| Tashqi havola | Bir qavat tashqaridagi muhit | buyurtmaBer uchun — global muhit |
Jadvaldagi misol — pastdagi «Qadamma-qadam» kodidan: buyurtmaBer(taom) funksiyasi global'da yozilgan va ichida const manzil bor. Uning muhiti — kichik daftar: ichida taom va manzil, muqovasida esa "tashqi daftar — global" degan yozuv.
Leksik muhit yaratiladi:
- global (yoki modul) uchun — dastur boshida bitta;
- har funksiya chaqiruvi uchun — yangisi (o'tgan darsdagi kontekst bilan birga);
- har blok uchun (
if,for,{ }). Bu faqat blokdalet,constyokiclassbo'lsa sezilarli — saqlaydigan nom bo'lmasa, blok muhiti bo'sh qoladi.
Eng tashqi muhitning tashqi havolasi — null: undan tashqarida hech narsa yo'q.
Tekshirib ko'ring: Global'da yozilgan
hisoblafunksiyasi ikki marta chaqirildi. Nechta funksiya muhiti yaratildi va ularning tashqi havolalari qayerga qaraydi?
Javob
Ikkita — har chaqiruvga bittadan, o'z o'zgaruvchilari bilan (Execution context). Ikkalasining tashqi havolasi esa bir xil — global muhitga: funksiya global'da yozilgan. Muhitlar har chaqiruvda yangi, zanjirning shakli esa doim bir xil.
2.2 O'xshatish: manzil
Bobur «Bahor»da telefonini qoldirib ketdi. Otabek uni qidiradi. Avval o'sha stolni ko'radi. Topmasa — zalni. Keyin butun choyxonani. Undan keyin — qidiradigan joy qolmadi: "topilmadi".
Ikki narsa muhim. Birinchidan, qidiruv doim ichkaridan tashqariga boradi: stol → zal → choyxona. Ikkinchidan, Otabek qo'shni kafening stollarini qidirmaydi — ular bu zanjirda yo'q. Scope zanjiri ham shunday: faqat o'z "ota-bobolar" muhitlari, qo'shnilar emas.
3. Scope zanjiri
3.1 Qidiruv qoidasi
Kod taom degan nomni ishlatdi. JavaScript qiymatni shunday topadi:
- Joriy muhitning jadvalidan qidiradi. Bor bo'lsa — shu, qidiruv to'xtaydi.
- Yo'q bo'lsa — tashqi havola bo'ylab bir qavat tashqariga chiqadi va yana 1-qadam.
- Havola
nullga yetsa —ReferenceError: taom is not defined.
Scope zanjiri (scope chain) — tashqi havolalar bilan bog'langan muhitlar ketma-ketligi. Bu ibora Scope asoslari darsida bir marta tilga olingan edi — endi ichini ko'ramiz.
3.2 Qadamma-qadam
Tanish misol — Scope asoslari darsidan. Endi har nom qanday topilishini kuzatamiz. Keyingi tugmasini bosing va izohdagi "qidiruv yo'li"ga qarang:
Zanjirning o'zi — sxemada. Har strelka — "tashqi havola":
flowchart LR
B["if bloki<br/>vaqt"] -- "tashqi" --> F["buyurtmaBer<br/>taom, manzil"]
F -- "tashqi" --> G["global<br/>shahar, buyurtmaBer"]
G -- "tashqi" --> N["null"]O'zingiz to'ldiring: 7-qatorda shahar ni topish uchun JavaScript ta muhitga qaradi.
3.3 Birinchi topilgani yutadi
Qidiruv birinchi mos nomda to'xtaydi. Tashqarida xuddi shu nom bo'lsa ham, unga yetib bormaydi:
const narx = 35000;
function aksiya() {
const narx = 30000;
if (narx < 35000) {
console.log(`Aksiya narxi: ${narx}`);
}
}
aksiya(); // Aksiya narxi: 30000
console.log(narx); // 35000if ichidagi narx: blokda yo'q → funksiyada bor (30000) → qidiruv to'xtadi. Global narx ga navbat kelmadi. Bu — soyalash (shadowing), endi uning mexanizmi aniq: tashqi nom o'chmagan, shunchaki zanjirda undan oldin boshqasi turibdi.
Tekshirib ko'ring:
aksiyaichida globalnarx(35 000) ni ham ishlatish kerak bo'lib qoldi. Ichkiconst narxturganda unga yetib borish mumkinmi?
Javob
Yo'q. Funksiya ichida narx nomi har doim ichkisiga tegishli — qidiruv unda to'xtaydi. Yagona yo'l — ichki o'zgaruvchini boshqacha nomlash (aksiyaNarxi). Shuning uchun soyalashdan ataylab foydalanmaslik maslahat beriladi.
3.4 O'zgartirish ham zanjir bo'ylab
Qiymat berishda ham nom xuddi shu yo'l bilan qidiriladi:
let jami = 0;
function qosh(summa) {
jami += summa;
}
qosh(35000);
qosh(5000);
console.log(jami); // 40000qosh ichida jami yo'q — zanjir bo'ylab global'dagi topildi va o'sha o'zgaruvchi o'zgardi. Yangi o'zgaruvchi yaratilmadi.
Agar nom zanjirning hech yerida bo'lmasa-chi? Zamonaviy kodda — modullarda — bu xato:
function qosh(summa) {
jamii += summa;
}
qosh(35000);ReferenceError: jamii is not definedTarjimasi: "jamii aniqlanmagan". Zanjir null gacha yetdi — topilmadi. Eski, modul bo'lmagan skriptlarda esa bunday tayinlash xatosiz yangi global o'zgaruvchi yaratib yuborardi. Bu xavfli "jim" xulq, uni Strict mode darsida ko'ramiz.
Tekshirib ko'ring: Ichki funksiya tashqi funksiyaning
consto'zgaruvchisini o'qiy oladimi? Tashqi funksiya ichkisining o'zgaruvchisini-chi?
Javob
Ichkisi tashqisinikini — ha: tashqi funksiya muhiti ichkisining zanjirida bor. Tashqisi ichkisinikini — yo'q: havolalar faqat tashqariga qaraydi. Tashqi funksiyaning zanjirida ichki muhit umuman yo'q.
4. Leksik scope: "qayerda yozilgan" muhim
4.1 Tashqi havola qachon belgilanadi
Endi «Nega bu kerak?» bo'limidagi jumboqqa qaytamiz. Hal qiluvchi savol: nomniAyt muhitining tashqi havolasi qayerga qaraydi?
Javob: funksiya yaratilgan joyga. JavaScript function nomniAyt() {...} ni ro'yxatga olayotganda funksiyaga uning tug'ilgan muhitini "yozib qo'yadi". nomniAyt global'da yozilgan — demak har chaqiruvda uning muhiti global'ga bog'lanadi. Kim chaqirgani ahamiyatsiz.
flowchart TB
G["global<br/>choyxona = 'Bahor'"]
K["boshqaKafe muhiti<br/>choyxona = 'Lola'"] -- "tashqi" --> G
N["nomniAyt muhiti<br/>(bo'sh)"] -- "tashqi" --> G
K -. "chaqiradi" .-> NUzluksiz strelkalar — tashqi havolalar, ikkalasi ham global'ga. Uzuq-uzuq strelka — chaqiruv: u stekka ta'sir qiladi (Execution context), scope zanjiriga esa yo'q. nomniAyt ichida choyxona qidirilganda, yo'l: o'z muhiti (bo'sh) → global → "Bahor". boshqaKafe ning muhiti bu yo'lda yo'q.
Ikki tuzilmani adashtirmang:
| Call stack | Scope zanjiri | |
|---|---|---|
| Nimani ko'rsatadi | Kim kimni chaqirdi | Kim qayerda yozildi |
| Qachon belgilanadi | Bajarilish paytida | Kod yozilganda |
| Nimaga kerak | Qayerga qaytishni bilish | Nomni topish |
Leksik (statik) scope (lexical scope) — nom kod matnidagi joylashuvga qarab qidiriladi. JavaScript, Python, C, Java va zamonaviy tillarning deyarli hammasi shunday ishlaydi.
4.2 Taqqoslash uchun: dinamik scope
Boshqacha qoida ham bor. Dinamik scope (dynamic scope) — nom chaqiruvlar zanjiri bo'ylab qidiriladi: avval chaqirgan funksiyada, keyin uni chaqirganda. Bunday tilda jumboqning javobi "Lola" bo'lardi.
Uni terminalda ko'rish mumkin: Bash'dagi local o'zgaruvchilar dinamik ishlaydi. Bash'da funksiya yozishni hali o'rganmagansiz — kodni to'liq tushunish shart emas, natijaga qarang. Xuddi shu jumboq:
choyxona="Bahor"
nomni_ayt() {
echo "$choyxona"
}
boshqa_kafe() {
local choyxona="Lola"
nomni_ayt
}
nomni_ayt
boshqa_kafeGit Bash'da (bash 5.3) natija:
Bahor
LolaBash'da nomni_ayt ni boshqa_kafe ichidan chaqirganda u chaqirganning choyxona sini ko'rdi. JavaScript'da esa — yo'q. Dinamik scope'da funksiyaning natijasi uni kim chaqirganiga bog'liq bo'lib qoladi — kodni faqat o'qib, xulqini aytib bo'lmaydi. Leksik scope'da esa funksiyaga qarab, u qaysi o'zgaruvchilarni ko'rishini aniq aytasiz. Zamonaviy tillar shu sababli leksik scope'ni tanlagan.
Maslahat: JavaScript'da dinamik scope'ga o'xshash bitta narsa bor —
this. Uning qiymati funksiya qanday chaqirilganiga bog'liq. Shuning uchunthisboshlovchilarni ko'p chalg'itadi. Unithis: to'rt qoida darsida alohida o'rganamiz.
Tekshirib ko'ring:
nomniAytniboshqaKafening ichida e'lon qilsak, jumboqning javobi o'zgaradimi?
Javob
Ha — "Lola" chiqadi. Endi nomniAyt boshqaKafe ichida yozilgan, uning tashqi havolasi — boshqaKafe ning muhiti. Qidiruv: o'z muhiti → boshqaKafe ("Lola" — topildi). Chaqiruv tartibi emas, yozilgan joy o'zgardi — natija ham o'zgardi.
4.3 Callback'lar ham yozilgan joyini ko'radi
Bu qoida HOF metodlarida ayniqsa muhim. Callback imzosi darsidagi harBirigaQil ni eslang — forEach ning o'z nusxamiz. Callback'ni u chaqiradi, lekin callback boshqa joyda yozilgan:
function harBirigaQil(massiv, amal) {
for (let i = 0; i < massiv.length; i++) {
amal(massiv[i]);
}
}
function menyuniChiqar(choyxona) {
const taomlar = ["Osh", "Manti"];
harBirigaQil(taomlar, (taom) => {
console.log(`${choyxona}: ${taom}`);
});
}
menyuniChiqar("Bahor");Konsolda:
Bahor: Osh
Bahor: MantiArrow funksiya menyuniChiqar ichida yozilgan. Uning zanjiri: o'z muhiti (taom) → menyuniChiqar (choyxona, taomlar) → global. Shuning uchun choyxona topildi — garchi callback'ni harBirigaQil chaqirgan bo'lsa ham.
Teskarisi ham to'g'ri: callback harBirigaQil ning i sini ko'rmaydi. i ni callback ichida ishlatsangiz — ReferenceError: i is not defined. Callback'ga harBirigaQil dan biror qiymat kerak bo'lsa, u faqat argument bilan keladi. Massiv metodlari callback'ga (element, index, array) ni aynan shu sababli argument qilib beradi.
Tekshirib ko'ring: 09-qismdagi
royxat.addEventListener("click", (event) => {...})tinglovchisi ichidaholatishlatiladi. Tinglovchini brauzer chaqiradi. Nega uholatni ko'radi?
Javob
Tinglovchi — arrow funksiya — vazifalar.js ning yuqori darajasida yozilgan. Uning zanjiri: o'z muhiti → skript muhiti (holat, royxat va boshqalar) → global. Kim chaqirgani — brauzer — ahamiyatsiz. Brauzer esa unga faqat bitta narsani argument qilib beradi: event obyektini.
4.4 Zanjir kod yozilganda ma'lum
Leksik scope'ning yana bir foydasi: zanjirni kod ishga tushmasdan oldin bilish mumkin. Funksiyaga qarab, uning ichidagi har nom qayerdan olinishini aytasiz — hech narsani ishga tushirmasdan. JavaScript dvigateli ham shundan foydalanadi: u kodni o'qiyotgandayoq ko'p nomlarning joyini aniqlab qo'yadi, shuning uchun uzun zanjir ham sekinlashtirmaydi.
Muharrir ham shunday ishlaydi. VS Code'da o'zgaruvchi ustiga sichqonchani olib borsangiz yoki F12 bossangiz, u nomning e'loniga sakraydi — dasturni ishga tushirmasdan. Bu faqat leksik scope'da mumkin: dinamik scope'da javob "kim chaqirishiga" bog'liq bo'lardi.
5. DevTools'da scope zanjiri
DevTools bilan debug qilish darsidagi Scope bo'limi — aynan scope zanjiri. Breakpoint'da to'xtaganingizda u joriy muhitdan boshlab tashqariga qarab ro'yxat chiqaradi:
| Bo'lim | Qaysi muhit |
|---|---|
| Block | if/for bloki (let/const bo'lsa) |
| Local | Joriy funksiya |
| Script | Oddiy <script> lardagi yuqori darajadagi let/const |
| Global | window — brauzer global obyekti |
vazifalar.js oddiy <script> bilan ulangan: holat, forma, royxat Script bo'limida ko'rinadi. Modul faylda (type="module") o'rniga Module bo'limi chiqadi. Ichma-ich funksiyalarda boshqa nomli bo'lim ham paydo bo'lishi mumkin — u Closure darsining mavzusi.
6. Ko'p uchraydigan xatolar
6.1 Chaqirgan joyning o'zgaruvchisini kutish
function chekniChiqar() {
console.log(`${stol}-stol uchun chek`);
}
function stolniYop() {
const stol = 7;
chekniChiqar();
}
stolniYop();ReferenceError: stol is not definedTarjimasi: "stol aniqlanmagan". chekniChiqar ning zanjiri: o'z muhiti → global. stolniYop ning muhiti unda yo'q. Tuzatish: kerakli qiymatni parametr qilib bering: chekniChiqar(stol). Bu yaxshiroq ham: funksiya nimaga bog'liqligi imzosidan ko'rinadi (Pure funksiya).
6.2 Imlo xatosi — "aniqlanmagan"
const narx e'lon qilib, narxi deb ishlatsangiz — zanjirning hech yerida narxi yo'q: ReferenceError: narxi is not defined. Tuzatish: xabardagi nomni e'londagi nom bilan harfma-harf solishtiring. VS Code'da nomni F2 bilan qayta nomlang — hamma joyda birdan o'zgaradi.
6.3 Ichki nom tashqisini yashirib qo'yadi
«Birinchi topilgani yutadi» bo'limidagi holat ataylab bo'lmasa — xato. Funksiya ichida tashqidagi bilan bir xil nomli o'zgaruvchi e'lon qilsangiz, tashqisiga endi yetib bo'lmaydi. Tuzatish: ichki nomni aniqroq qiling (aksiyaNarxi). ESLint'ning no-shadow qoidasi buni avtomatik topadi (ESLint — 12-qismda).
6.4 Qo'shni funksiyaning o'zgaruvchisi
function bronQil() {
const bronRaqami = 17;
console.log(`Bron: ${bronRaqami}`);
}
function bronniBekorQil() {
console.log(`Bekor: ${bronRaqami}`);
}
bronQil();
bronniBekorQil();ReferenceError: bronRaqami is not definedIkki funksiya yonma-yon yozilgan — ular bir-birining ichini ko'rmaydi. bronniBekorQil ning zanjiri: o'z muhiti → global. bronQil ning muhiti bu yo'lda yo'q, ustiga u allaqachon tugab, yo'qolgan. Tuzatish: ma'lumotni return bilan qaytaring va keyingi funksiyaga parametr qilib bering: bronniBekorQil(bronQil()). Yoki ikkalasi ishlatadigan qiymatni umumiy tashqi muhitga — masalan, holat obyektiga — qo'ying.
7. Mashqlar
1-mashq (oson): Qaysi qiymat?
Ishga tushirmasdan, har console.log nima chiqarishini ayting:
const taom = "osh";
function birinchi() {
const taom = "manti";
console.log(taom);
}
function ikkinchi() {
console.log(taom);
}
birinchi();
ikkinchi();
console.log(taom);Yechim
Konsolda:
manti
osh
oshbirinchi da taom o'z muhitida topildi — "manti". ikkinchi ning muhitida taom yo'q — global'dan "osh". birinchi ning ichki taom i boshqalarga ta'sir qilmaydi: u faqat birinchi ning muhitida.
2-mashq (o'rta): Zanjirni yozing
Belgilangan qatorda har nom (ism, soni, chegirma, narx) qaysi muhitda topilishini va nechta muhitga qaralganini yozing.
const chegirma = 10;
function hisobla(ism) {
const narx = 35000;
for (let soni = 1; soni <= 2; soni++) {
const jami = narx * soni - (narx * soni * chegirma) / 100;
console.log(`${ism}: ${soni} ta — ${jami}`); // shu qator
}
}
hisobla("Bobur");Yechim
Konsolda:
Bobur: 1 ta — 31500
Bobur: 2 ta — 63000Zanjir: for tanasi bloki (jami) → for boshidagi let soni muhiti → hisobla muhiti (ism, narx) → global (chegirma, hisobla).
| Nom | Topilgan muhit | Nechta muhitga qaraldi |
|---|---|---|
jami |
for tanasi |
1 |
soni |
for boshi |
2 |
ism |
hisobla |
3 |
chegirma |
global | 4 |
for (let ...) o'z muhitini yaratadi, tanasi { } esa — yana bittasini. narx ham hisobla muhitida — ism kabi 3 ta muhitga qarab topiladi.
3-mashq (qiyin): Yashirin bog'liqlikni tuzating
Bu kod "dinamik scope" kutib yozilgan va ishlamaydi. Uni shunday tuzatingki, chekYoz hech qanday tashqi o'zgaruvchiga tayanmasin — hamma narsa parametr orqali kelsin. Natija: 7-stol: Osh × 2 = 70000 so'm.
const narxlar = { Osh: 35000, Manti: 30000 };
function chekYoz() {
const narx = narxlar[taom];
return `${stol}-stol: ${taom} × ${soni} = ${narx * soni} so'm`;
}
function buyurtmaniYop(stol, taom, soni) {
console.log(chekYoz());
}
buyurtmaniYop(7, "Osh", 2);Yechim
const narxlar = { Osh: 35000, Manti: 30000 };
function chekYoz(stol, taom, soni, menyu) {
const narx = menyu[taom];
return `${stol}-stol: ${taom} × ${soni} = ${narx * soni} so'm`;
}
function buyurtmaniYop(stol, taom, soni) {
console.log(chekYoz(stol, taom, soni, narxlar));
}
buyurtmaniYop(7, "Osh", 2); // 7-stol: Osh × 2 = 70000 so'mAsl kodda chekYoz ning zanjiri: o'z muhiti → global. stol, taom, soni — buyurtmaniYop ning parametrlari, ular zanjirda yo'q: ReferenceError: taom is not defined. Endi barcha qiymatlar parametr orqali keladi. Global narxlar ni ham parametr qildik — chekYoz endi toza funksiya: uni istalgan menyu bilan sinash mumkin. Global'ni o'qish xato emas, lekin funksiya qancha kam tashqi nomga tayansa, shuncha tushunarli.
4-mashq: Vazifalar qadami — fokusla ning zanjiri
vazifalar.js ni o'zgartirmaymiz — o'qiymiz. Javob: kurs/mashqlar/10/20-scope/javoblar.md.
vazifalar.js dagi fokusla funksiyasi:
function fokusla(id, amal, zaxiraId) {
const top = (i) =>
royxat.querySelector(`[data-id="${i}"] [data-amal="${amal}"]`);
const nishon = top(id) ?? top(zaxiraId) ?? sarlavha;
nishon.focus();
}toparrow funksiyasi ichida uchta nom ishlatilgan:i,royxat,amal(querySelector— nom emas,royxatning metodi). Har nom qaysi muhitda topiladi?topmuhitidannullgacha bo'lgan scope zanjirini mermaid sxema qilib chizing.- DevTools'da tekshiring:
topichiga breakpoint qo'yib, vazifani belgilang. Scope bo'limida qaysi bo'limlar chiqdi? - Savol:
topnifokusladan tashqariga, global darajaga ko'chirsak ishlaydimi? Nega?
Yechim
i—topning o'z parametri (1 qadam).amal—fokuslaning parametri (2 qadam).royxat— skriptning yuqori darajasidagiconst(3 qadam).- Sxema (
javoblar.mdga ```mermaid bloki):
flowchart LR
T["top<br/>i"] -- "tashqi" --> F["fokusla<br/>id, amal, zaxiraId, top, nishon"]
F -- "tashqi" --> S["skript<br/>holat, royxat, sarlavha …"]
S -- "tashqi" --> G["global<br/>window"]
G -- "tashqi" --> N["null"]- Scope bo'limida: Local (
i), keyinfokuslamuhiti (amal,idva boshqalar — Chrome uni alohida nom bilan ko'rsatadi, u nima ekanini Closure darsida bilib olasiz), Script (holat,royxat, ...), Global. - Yo'q.
topamalni ishlatadi. Global darajada yozilsa, uning zanjiri: o'z muhiti → skript → global.fokuslaning muhiti — va undagiamal— zanjirdan chiqib qoladi:ReferenceError: amal is not defined.topataylabfokuslaichida yozilgan: ikki marta chaqiriladigan qidiruvgaamalni har safar parametr qilib bermaslik uchun. Ko'chirish kerak bo'lsa —amalni ikkinchi parametr qiling:top(i, amal).
Commit — mashqlar repoda:
git add 10/20-scope/javoblar.md
git commit -m "10/20: fokusla ning scope zanjirini chiz"8. Real ishda
- Kod o'qish. Katta loyihada funksiya qaysi nomga tayanishini bilish uchun uni chaqirgan joylarni qidirish shart emas — funksiya yozilgan joyning atrofiga qarash yetadi. Leksik scope tufayli kodni bo'lak-bo'lak tushunish mumkin.
- Vositalar. VS Code'ning "Go to Definition" (
F12) va qayta nomlash (F2) aynan leksik scope'ga tayanadi: muharrir nom qaysi e'longa tegishli ekanini dasturni ishga tushirmasdan biladi. Dinamik scope'da bu mumkin bo'lmasdi. - Callback'lar.
forEachyokiaddEventListenerga bergan funksiyangiz o'zi yozilgan joydagi o'zgaruvchilarni ko'radi — uni brauzer yoki massiv metodi chaqirsa ham. 09-qismdagi tinglovchilarholatni shu tufayli ko'radi. - Intervyu. "Lexical scope nima?", "scope chain qanday ishlaydi?" va jumboqqa o'xshash "bu kod nima chiqaradi?" savollari — closure savollaridan oldingi odatiy qadam.
Xulosa
- Leksik muhit — nomlar jadvali + tashqi muhitga havola. U global, har funksiya chaqiruvi va
let/constli har blok uchun yaratiladi. - Scope zanjiri — tashqi havolalar ketma-ketligi. Nom ichkaridan tashqariga qidiriladi, birinchi topilgani olinadi;
nullgacha topilmasa —ReferenceError. - Tashqi havola funksiya yozilgan joyga qarab belgilanadi, chaqirilgan joyga emas — bu leksik scope.
- Call stack — kim kimni chaqirdi; scope zanjiri — kim qayerda yozildi. Ular mustaqil.
- Dinamik scope (Bash'dagi
local) chaqiruv bo'ylab qidiradi; JavaScript'da faqatthisshunga o'xshaydi.
Keyingi dars: Hoisting: e'lonlar "ko'tarilishi" — yaratish bosqichida har xil e'lon (function, var, let, const, function expression) qanday ro'yxatga olinishini birma-bir ko'ramiz.
Manbalar
- ECMAScript 2025 Language Specification: "Environment Records", "ResolveBinding", "GetIdentifierReference" — tc39.es/ecma262
- MDN: "Scope" (Glossary), "Closures" — "Lexical scoping" bo'limi — developer.mozilla.org
- GNU Bash Reference Manual: "Shell Functions" (
localva dinamik scope) — gnu.org/software/bash/manual
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!