IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur20/65-dars17 daqiqa
Mundarija (29)

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.js dagi 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?

js
const choyxona = "Bahor";

function nomniAyt() {
  console.log(choyxona);
}

function boshqaKafe() {
  const choyxona = "Lola";
  nomniAyt();
}

boshqaKafe(); // Bahor

Ko'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 blokda let, const yoki class bo'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 hisobla funksiyasi 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:

  1. Joriy muhitning jadvalidan qidiradi. Bor bo'lsa — shu, qidiruv to'xtaydi.
  2. Yo'q bo'lsa — tashqi havola bo'ylab bir qavat tashqariga chiqadi va yana 1-qadam.
  3. Havola null ga 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:

js
const narx = 35000;

function aksiya() {
  const narx = 30000;
  if (narx < 35000) {
    console.log(`Aksiya narxi: ${narx}`);
  }
}

aksiya(); // Aksiya narxi: 30000
console.log(narx); // 35000

if 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: aksiya ichida global narx (35 000) ni ham ishlatish kerak bo'lib qoldi. Ichki const narx turganda 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:

js
let jami = 0;

function qosh(summa) {
  jami += summa;
}

qosh(35000);
qosh(5000);
console.log(jami); // 40000

qosh 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:

js
function qosh(summa) {
  jamii += summa;
}

qosh(35000);
text
ReferenceError: jamii is not defined

Tarjimasi: "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 const o'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" .-> N

Uzluksiz 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:

bash
choyxona="Bahor"

nomni_ayt() {
  echo "$choyxona"
}

boshqa_kafe() {
  local choyxona="Lola"
  nomni_ayt
}

nomni_ayt
boshqa_kafe

Git Bash'da (bash 5.3) natija:

text
Bahor
Lola

Bash'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 uchun this boshlovchilarni ko'p chalg'itadi. Uni this: to'rt qoida darsida alohida o'rganamiz.

Tekshirib ko'ring: nomniAyt ni boshqaKafe ning 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:

js
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:

text
Bahor: Osh
Bahor: Manti

Arrow 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 ichida holat ishlatiladi. Tinglovchini brauzer chaqiradi. Nega u holat ni 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

js
function chekniChiqar() {
  console.log(`${stol}-stol uchun chek`);
}

function stolniYop() {
  const stol = 7;
  chekniChiqar();
}

stolniYop();
text
ReferenceError: stol is not defined

Tarjimasi: "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

js
function bronQil() {
  const bronRaqami = 17;
  console.log(`Bron: ${bronRaqami}`);
}

function bronniBekorQil() {
  console.log(`Bekor: ${bronRaqami}`);
}

bronQil();
bronniBekorQil();
text
ReferenceError: bronRaqami is not defined

Ikki 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:

js
const taom = "osh";

function birinchi() {
  const taom = "manti";
  console.log(taom);
}

function ikkinchi() {
  console.log(taom);
}

birinchi();
ikkinchi();
console.log(taom);
Yechim

Konsolda:

text
manti
osh
osh

birinchi 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.

js
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:

text
Bobur: 1 ta — 31500
Bobur: 2 ta — 63000

Zanjir: 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.

js
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
js
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'm

Asl 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:

js
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();
}
  1. top arrow funksiyasi ichida uchta nom ishlatilgan: i, royxat, amal (querySelector — nom emas, royxat ning metodi). Har nom qaysi muhitda topiladi?
  2. top muhitidan null gacha bo'lgan scope zanjirini mermaid sxema qilib chizing.
  3. DevTools'da tekshiring: top ichiga breakpoint qo'yib, vazifani belgilang. Scope bo'limida qaysi bo'limlar chiqdi?
  4. Savol: top ni fokusla dan tashqariga, global darajaga ko'chirsak ishlaydimi? Nega?
Yechim
  1. i — top ning o'z parametri (1 qadam). amal — fokusla ning parametri (2 qadam). royxat — skriptning yuqori darajasidagi const (3 qadam).
  2. Sxema (javoblar.md ga ```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"]
  1. Scope bo'limida: Local (i), keyin fokusla muhiti (amal, id va boshqalar — Chrome uni alohida nom bilan ko'rsatadi, u nima ekanini Closure darsida bilib olasiz), Script (holat, royxat, ...), Global.
  2. Yo'q. top amal ni ishlatadi. Global darajada yozilsa, uning zanjiri: o'z muhiti → skript → global. fokusla ning muhiti — va undagi amal — zanjirdan chiqib qoladi: ReferenceError: amal is not defined. top ataylab fokusla ichida yozilgan: ikki marta chaqiriladigan qidiruvga amal ni har safar parametr qilib bermaslik uchun. Ko'chirish kerak bo'lsa — amal ni ikkinchi parametr qiling: top(i, amal).

Commit — mashqlar repoda:

bash
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. forEach yoki addEventListener ga bergan funksiyangiz o'zi yozilgan joydagi o'zgaruvchilarni ko'radi — uni brauzer yoki massiv metodi chaqirsa ham. 09-qismdagi tinglovchilar holat ni 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/const li har blok uchun yaratiladi.
  • Scope zanjiri — tashqi havolalar ketma-ketligi. Nom ichkaridan tashqariga qidiriladi, birinchi topilgani olinadi; null gacha 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 faqat this shunga 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" (local va dinamik scope) — gnu.org/software/bash/manual
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript leksik scope va scope zanjiri: o'zgaruvchi qayerdan topiladi — IlmHamroh