Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Execution context nima?
- 2.1 Ta'rif
- 2.2 Ikki asosiy tur
- 3. Ikki bosqich: yaratish va bajarish
- 3.1 Bosqichlar
- 3.2 Isbot
- 3.3 Global kontekst ham ikki bosqichli
- 4. Call stack: kontekstlar taxlami
- 4.1 Qadamma-qadam
- 4.2 Har chaqiruv — yangi kontekst
- 5. Stack trace — stekning surati
- 5.1 Xato paytidagi stek
- 5.2 Jonli stek
- 6. Bitta stek — bir vaqtda bitta ish
- 7. Ko'p uchraydigan xatolar
- 7.1 Funksiya o'zgaruvchisi chaqiruvlar orasida "saqlanadi" deb kutish
- 7.2 Bir-birini cheksiz chaqiradigan funksiyalar
- 7.3 E'lonni chaqiruv deb o'ylash
- 8. Mashqlar
- 1-mashq (oson): Stekni chizing
- 2-mashq (o'rta): Tartibni oldindan ayting
- 3-mashq (qiyin): Ikki funksiyali rekursiya
- 4-mashq: Vazifalar qadami — bitta bosishning yo'li
- 9. Real ishda
- Xulosa
- Manbalar
JavaScript execution context va call stack: kod ichidan qanday bajariladi
Qisqacha: Execution context (bajarilish konteksti) — JavaScript kodni bajarayotganda yuritadigan "ish varag'i": qaysi o'zgaruvchilar bor, ular qanday qiymatda va tashqi muhit qaysi. Dastur boshida bitta global kontekst yaratiladi, keyin har funksiya chaqiruvi o'z yangi kontekstini oladi. Har kontekst ikki bosqichdan o'tadi — avval yaratish (e'lonlar ro'yxatga olinadi), keyin bajarish (qatorma-qator). Kontekstlar chaqiruvlar stekiga (call stack) joylanadi: tepadagisi bajariladi, tugagach olib tashlanadi.
Bu darsda
- Execution context nima ekanini va unda nimalar saqlanishini tushuntira olasiz.
- Global va funksiya kontekstini farqlaysiz.
- Yaratish va bajarish bosqichlarida nima bo'lishini qadamma-qadam ayta olasiz.
- Kod bajarilayotganda call stack'ni qog'ozda chiza olasiz va stack trace'ni kontekstlar ro'yxati sifatida o'qiysiz.
vazifalarda bitta bosish qaysi funksiyalar zanjiridan o'tishini DevTools'da ko'rasiz.
Oldin bilishingiz kerak: Rekursiya asoslari, DevTools bilan debug qilish, Scope asoslari, Stack trace va xato turlari.
1. Nega bu kerak?
08-qismda bir nechta "g'alati" qoidalarni ko'rgan edik:
functionbilan e'lon qilingan funksiyani e'londan oldin chaqirsa bo'ladi (Funksiya e'lon qilish).varo'zgaruvchi e'londan oldinundefined,letesa xato beradi (varva nega undan voz kechildi).- Funksiyaning har chaqiruvida o'zgaruvchilar yangidan yaratiladi (Scope asoslari).
- Funksiya tugagach, JavaScript aynan chaqirilgan joyga qaytadi (Rekursiya asoslari).
Har birini alohida yodlash mumkin. Lekin ularning hammasi bitta mexanizmdan kelib chiqadi. Shu mexanizmni tushunsangiz, to'rttala qoida "o'z-o'zidan" ma'lum bo'ladi. Bugun va keyingi uch darsda aynan shu mexanizmni ochamiz: execution context, scope zanjiri, hoisting va TDZ.
Hayotdan o'xshatish. «Bahor» oshxonasida har buyurtma uchun alohida varaq yoziladi: qaysi stol, nima taom, nechta, izoh. Rustam aka varaqlarni ilgichga birin-ketin ilib boradi va doim eng ustidagi varaq bo'yicha ishlaydi. Tayyor bo'lgach, varaqni olib tashlaydi va pastdagisiga qaytadi. Ikki stol bir xil osh buyursa ham — ikkita alohida varaq: biri 2 ta, biri 5 ta.
JavaScript'da varaq — execution context, ilgich — call stack.
2. Execution context nima?
2.1 Ta'rif
Bajarilish konteksti (execution context) — JavaScript hozir bajarayotgan kod uchun yuritadigan ichki yozuv. Unda uchta narsa bor:
| Qism | Nima saqlanadi | Qaysi darsda chuqur |
|---|---|---|
| O'zgaruvchilar | Parametrlar, let, const, var, funksiyalar — nomi va qiymati |
shu dars |
| Tashqi havola | Topilmagan nomni qayerdan qidirish | Leksik scope |
this |
Maxsus so'zning qiymati | this |
Bu yozuvni kodda ko'rmaysiz va unga murojaat qila olmaysiz. U JavaScript dvigatelining ichida yashaydi. Lekin uning izlari hamma joyda: DevTools'dagi Scope bo'limi — joriy kontekstning o'zgaruvchilari, Call Stack — kontekstlar ro'yxati (DevTools bilan debug qilish).
Ikki atamani adashtirmang. Scope — kod matnidagi hudud: qaysi nom qayerda ko'rinadi. U kod yozilganda belgilanadi. Kontekst — bajarilish paytidagi yozuv. U funksiya chaqirilganda yaratiladi va tugaganda yo'qoladi. Bitta funksiyaning scope'i bitta, kontekstlari esa har chaqiruvda yangi.
2.2 Ikki asosiy tur
Global kontekst — dastur boshlanganda yaratiladi, faqat bitta. Unda fayl darajasidagi nomlar yashaydi: yuqori darajadagi const, let va funksiyalar.
Funksiya konteksti — har funksiya chaqiruvida yangisi yaratiladi. Funksiyani e'lon qilish kontekst yaratmaydi — faqat chaqirish.
Maslahat: Node'dagi
.mjsfayl va brauzerdagi<script type="module">da faylning yuqori darajasi — modul konteksti. U global kontekstdan bir qavat ichkarida turadi. Bu darsdagi misollar uchun farqi yo'q — biz ikkalasini "global" deymiz. Farqini Global obyekt vaglobalThisva modullar darslarida ko'ramiz.evaluchun ham alohida kontekst bor, lekinevalishlatilmaydi (evalvanew Function).
Tekshirib ko'ring: Faylda 5 ta funksiya e'lon qilingan, ulardan bittasi 3 marta chaqirildi. Dastur davomida nechta kontekst yaratildi?
Javob
4 ta: bitta global va uchta funksiya konteksti. E'lon qilingan, lekin chaqirilmagan to'rtta funksiya hech qanday kontekst yaratmaydi. Bir funksiyaning uch chaqiruvi esa uchta alohida kontekst — har birida o'z o'zgaruvchilari.
3. Ikki bosqich: yaratish va bajarish
3.1 Bosqichlar
Kontekst bir zumda "tayyor" bo'lmaydi. Har kontekst ikki bosqichdan o'tadi:
- Yaratish bosqichi (creation phase). Kod hali bajarilmaydi. JavaScript funksiya tanasini (yoki butun faylni) bir marta ko'zdan kechirib, barcha e'lonlarni ro'yxatga oladi:
- parametrlar — chaqiruvdagi argumentlar bilan;
functione'lonlari — to'liq funksiya bilan;var—undefinedbilan;letvaconst— nom yoziladi, lekin qiymat yo'q ("tayyor emas" belgisi bilan).
- Bajarish bosqichi (execution phase). Endi kod yuqoridan pastga, qatorma-qator bajariladi. Tayinlashlar qiymat beradi, chaqiruvlar yangi kontekst ochadi.
Maktab jurnali o'xshatishini eslang (var darsi): o'quv yili boshida o'qituvchi jurnalga barcha ismlarni yozadi — bu yaratish. Baholar esa dars bo'lganda qo'yiladi — bu bajarish.
3.2 Isbot
Yaratish bosqichini o'z ko'zimiz bilan ko'ramiz. Funksiya boshida — hali hech bir qator bajarilmasdan — nomlarga qaraymiz:
function chekYoz(soni) {
console.log(soni); // 2
console.log(typeof hisobla); // function
console.log(izoh); // undefined
var izoh = "Rahmat!";
function hisobla() {
return 35000 * soni;
}
return `${hisobla()} so'm. ${izoh}`;
}
console.log(chekYoz(2)); // 70000 so'm. Rahmat!Birinchi uchta console.log funksiyaning birinchi qatorlari. Lekin:
soniallaqachon2— parametr yaratish bosqichida to'ldirildi.hisoblaallaqachon funksiya — u 7-qatorda e'lon qilingan bo'lsa ham.izohmavjud, lekinundefined—"Rahmat!"faqat 6-qatorga yetganda beriladi.
Uchalasi ham bitta sababdan: kod bajarilishidan oldin yaratish bosqichi o'tdi. Endi let bilan:
function chekYoz() {
console.log(izoh);
let izoh = "Rahmat!";
}
chekYoz();ReferenceError: Cannot access 'izoh' before initializationTarjimasi: "izoh ga boshlang'ich qiymat berilishidan oldin murojaat qilib bo'lmaydi". Nom ro'yxatda bor — aks holda xabar izoh is not defined bo'lardi. Lekin qiymati yo'q, tegish taqiqlangan. Bu holatning nomi — TDZ, uni Temporal Dead Zone darsida, e'lonlarning "ko'tarilishi"ni esa Hoisting darsida to'liq ko'ramiz.
3.3 Global kontekst ham ikki bosqichli
Yaratish bosqichi faqat funksiyalarda emas. Global kontekst ham avval butun faylni ko'zdan kechiradi, keyin bajaradi:
console.log(chegirmaQol(100000)); // 90000
function chegirmaQol(summa) {
return summa - summa / 10;
}Funksiya e'lon qilish darsida bu "hiyla"ni ko'rgan edik va "kod yuqoridan pastga bajariladi" qoidasi bilan qanday kelishishini so'ragan edik. Endi javob aniq. Ikkala gap ham rost, faqat ular ikki xil bosqich haqida. Yaratish bosqichida chegirmaQol to'liq ro'yxatga olindi. Bajarish bosqichi esa haqiqatan 1-qatordan boshlandi — va shu paytda funksiya allaqachon tayyor edi.
Shuning uchun vazifalar.js da tinglovchilar faylning oxirida turgani muhim emas: ular chaqiradigan render, vazifaQosh va boshqalar yaratish bosqichidayoq tayyor bo'ladi. Lekin const holat — yo'q. Bu farqni Hoisting darsida vazifalar ning o'zida sinab ko'ramiz.
Kontekstning butun umri — bitta sxemada. Strelkalar bo'ylab o'qing:
flowchart LR
A["Chaqiruv:<br/>chekYoz(2)"] --> B["Yaratish:<br/>nomlar ro'yxatga"]
B --> C["Stek tepasiga<br/>qo'yiladi"]
C --> D["Bajarish:<br/>qatorma-qator"]
D -- "ichkarida chaqiruv" --> A
D -- "return yoki oxiri" --> E["Stekdan<br/>olib tashlanadi"]
E --> F["Chaqirgan joyga<br/>qaytish"]Ichkaridagi chaqiruv o'qi orqaga — A ga — qaytadi: yangi kontekst ham xuddi shu yo'ldan o'tadi va eskisining ustiga qo'yiladi.
Tekshirib ko'ring: Yaratish bosqichida
const narx = 35000;qatoridan nima ro'yxatga olinadi — nommi, qiymatmi yoki ikkalasi?
Javob
Faqat nom — narx, "tayyor emas" belgisi bilan. 35000 qiymati faqat bajarish bosqichida, kod shu qatorga yetganda beriladi. Shuning uchun undan oldin narx ni o'qish ReferenceError beradi.
4. Call stack: kontekstlar taxlami
4.1 Qadamma-qadam
Chaqiruvlar steki (call stack) — Rekursiya darsidan tanish: hozir bajarilayotgan chaqiruvlar ro'yxati, likoplar taxlamidek. Endi aniqroq ayta olamiz: stekning har qavati — bitta execution context.
Rekursiyasiz, oddiy zanjirda kuzatamiz. Keyingi tugmasini bosing. O'ngdagi "Chaqiruvlar steki" ga va har yangi kontekstdagi o'zgaruvchilarga qarang — avval "tayyor emas", keyin qiymat:
Uchta kuzatish:
- Bir xil nom — ikki o'zgaruvchi.
chekYozda ham,narxniOlda hamtaombor. Ular ikki kontekstda ikki alohida o'zgaruvchi. - Kutish.
chekYoz7-qatorda to'xtab turdi. U o'chmadi, stekdan chiqmadi — faqat ustiga boshqa kontekst qo'yildi. - Tugash — yo'qolish.
narxniOltugagach, uningmenyusi ham yo'qoldi. Kontekst o'zgaruvchilari shu kontekst bilan birga yashaydi.
Tekshirib ko'ring:
narxniOltugagach, uningmenyuo'zgaruvchisinichekYozichidan o'qish mumkinmi?
Javob
Yo'q. menyu faqat narxniOl kontekstida yashadi va u stekdan chiqishi bilan yo'qoldi. chekYoz ga faqat qaytarilgan qiymat — 35000 — keldi. Funksiyadan ma'lumot olib chiqishning yo'li — return.
4.2 Har chaqiruv — yangi kontekst
Bir funksiyani ketma-ket ikki marta chaqiramiz:
function stolHisobi(stol, soni) {
const jami = soni * 35000;
console.log(`${stol}-stol: ${jami}`);
}
stolHisobi(3, 2);
stolHisobi(7, 5);Konsolda:
3-stol: 70000
7-stol: 175000Ikkinchi chaqiruvda jami birinchisini "eslamaydi". Birinchi kontekst stekdan chiqqanda uning jami si ham ketdi. Ikkinchi chaqiruv yangi varaqdan boshladi. Scope asoslari darsidagi "har chaqiruvda — yangi o'zgaruvchilar" qoidasining ichki sababi shu.
Rekursiyada bir funksiyaning bir nechta konteksti stekda bir vaqtda turadi. faktorial(3) da uchta kontekst — har birida o'z n i: 3, 2, 1 (Rekursiya asoslari). Ular bir-biriga xalaqit bermaydi, chunki har biri alohida varaq.
O'zingiz to'ldiring: faktorial(5) chaqirilganda stekda bir vaqtda eng ko'pi bilan ta faktorial konteksti bo'ladi.
5. Stack trace — stekning surati
5.1 Xato paytidagi stek
Stack trace darsida at ... qatorlarini o'qishni o'rgandik. Endi ularning ma'nosi aniq: stack trace — xato yuz bergan paytdagi call stack'ning surati. Har at qatori — bitta kontekst. Eng tepadagisi — xato chiqqan kontekst.
chek.js:
const menyu = {
osh: { narx: 35000 },
manti: { narx: 30000 },
};
function narxniOl(taom) {
return menyu[taom].narx;
}
function chekYoz(taom, soni) {
const narx = narxniOl(taom);
return `${taom} × ${soni}: ${narx * soni} so'm`;
}
function buyurtmaBer(taom, soni) {
console.log(chekYoz(taom, soni));
}
buyurtmaBer("osh", 2);
buyurtmaBer("palov", 1);node chek.js — Node 24 (C:\... — yo'l qisqartirildi):
osh × 2: 70000 so'm
C:\...\10\chek.js:7
return menyu[taom].narx;
^
TypeError: Cannot read properties of undefined (reading 'narx')
at narxniOl (C:\...\10\chek.js:7:22)
at chekYoz (C:\...\10\chek.js:11:16)
at buyurtmaBer (C:\...\10\chek.js:16:15)
at Object.<anonymous> (C:\...\10\chek.js:20:1)
at Module._compile (node:internal/modules/cjs/loader:1929:14)
at Object..js (node:internal/modules/cjs/loader:2060:10)
at Module.load (node:internal/modules/cjs/loader:1651:32)
at Module._load (node:internal/modules/cjs/loader:1443:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)
at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)
Node.js v24.21.0at qatorlarini pastdan tepaga o'qing — stek shunday o'sgan:
at qatori |
Kontekst | Qayerda to'xtab turibdi |
|---|---|---|
Object.<anonymous> …:20:1 |
global (fayl) | 20-qator: buyurtmaBer("palov", 1) |
buyurtmaBer …:16:15 |
buyurtmaBer("palov", 1) |
16-qator: chekYoz ni kutyapti |
chekYoz …:11:16 |
chekYoz("palov", 1) |
11-qator: narxniOl ni kutyapti |
narxniOl …:7:22 |
narxniOl("palov") |
7-qator: xato shu yerda |
Har qatordagi raqam — o'sha kontekst to'xtab turgan joy: kimni kutayotgani. Birinchi buyurtmaBer("osh", 2) surati yo'q — u xatodan oldin tugab, stekdan chiqib bo'lgan edi. Pastdagi node:internal qatorlari — Node'ning o'z konteksti: u faylingizni ishga tushirgan kod. Node odatda faqat 10 ta qatorni ko'rsatadi.
5.2 Jonli stek
Xato bo'lmasa ham stekni ko'rish mumkin. DevTools bilan debug qilish darsida o'rganganingiz — Call Stack bo'limi: breakpoint'da to'xtaganda u joriy stekni ko'rsatadi. Ro'yxatdagi qatorni bossangiz, Scope bo'limi o'sha kontekstning o'zgaruvchilarini ko'rsatadi. Ya'ni DevTools stekdagi har varaqni varaqlab ko'rishga imkon beradi. Buni «Vazifalar qadami» da vazifalar ilovasida qilasiz.
Tekshirib ko'ring: Stack trace'da
at chekYoz (…chek.js:11:16)qatori bor. Xato 11-qatordami?
Javob
Yo'q. Xato 7-qatorda — eng tepadagi narxniOl da. chekYoz 11-qatorda to'xtab turgan edi: u narxniOl dan javob kutayotgan edi. Stack trace'dagi pastki qatorlar — xato joyi emas, unga olib kelgan yo'l.
6. Bitta stek — bir vaqtda bitta ish
JavaScript'da call stack bitta. Demak bir paytda faqat bitta kontekst — tepadagisi — bajariladi. Bu bir oqimli (single-threaded) bajarilish deyiladi.
Oqibati muhim. Tepadagi funksiya uzoq ishlasa — masalan, million elementli massivni aylansa — undan pastdagilar ham, boshqa hamma ish ham kutadi. Brauzerda bu sahifaning "qotishi"dir: tugma bosilishi, matn yozish, animatsiya — hammasi stek bo'shashini kutadi. Rustam aka bitta katta to'y oshi bilan band bo'lsa, ilgichdagi kichik buyurtmalar ham kutib turadi.
Unda tarmoqdan javob kutish yoki taymer qanday ishlaydi? Ular stekdan tashqarida kutadi va tayyor bo'lgach, stekka navbat bilan qo'yiladi. Bu mexanizm — event loop, uni 11-qismda, Event loop darsida o'rganamiz — hozir bilish shart emas. Hozircha bitta qoida: call stack'dagi ish tugamaguncha, keyingisi boshlanmaydi.
Tekshirib ko'ring: Tugma bosilganda ishlaydigan tinglovchi 5 soniya davom etadigan hisob qiladi. Shu 5 soniyada foydalanuvchi boshqa tugmani bossa nima bo'ladi?
Javob
Ikkinchi tugmaning tinglovchisi darhol ishlamaydi. Stekda birinchi tinglovchining konteksti turibdi — u tugamaguncha boshqa kod bajarila olmaydi. Brauzer bosishni eslab qoladi va stek bo'shagach ishlatadi. Foydalanuvchi esa 5 soniya "qotib qolgan" sahifani ko'radi. Shuning uchun tinglovchilar qisqa bo'lishi kerak.
7. Ko'p uchraydigan xatolar
7.1 Funksiya o'zgaruvchisi chaqiruvlar orasida "saqlanadi" deb kutish
function tashrifniSana() {
let soni = 0;
soni++;
return soni;
}
tashrifniSana();
tashrifniSana();
console.log(tashrifniSana()); // 1Uch marta chaqirildi, lekin javob 1. Har chaqiruv yangi kontekst, yangi soni = 0. Tuzatish: chaqiruvlar orasida saqlanishi kerak bo'lgan qiymat funksiyadan tashqarida yashashi kerak — masalan, holat obyektida (Holatdan UI chizish). Funksiya ichida "o'z xotirasi" bo'lgan hisoblagichni esa Closure amaliyotda darsida yasaymiz.
7.2 Bir-birini cheksiz chaqiradigan funksiyalar
function stolniTekshir(stol) {
return bronniTekshir(stol);
}
function bronniTekshir(stol) {
return stolniTekshir(stol);
}
stolniTekshir(4);RangeError: Maximum call stack size exceededRekursiya bitta funksiyada bo'lishi shart emas. Bu yerda ikki funksiya navbat bilan bir-birini chaqiradi va hech biri tugamaydi. Har chaqiruv stekka yangi kontekst qo'shadi — stek to'lib ketadi (Rekursiya asoslari). Tuzatish: stack trace'da bir xil ikki nom navbatma-navbat takrorlansa — shu ikki funksiyaning qaysi biri to'xtashi kerakligini toping.
7.3 E'lonni chaqiruv deb o'ylash
function hisobla() { ... } yozilishi bilan hech narsa bajarilmaydi va kontekst yaratilmaydi. Funksiya faqat ro'yxatga olinadi. hisobla() — qavslar bilan chaqirilganda — kontekst paydo bo'ladi. Debug paytida "funksiya ishlamayapti" desangiz, avval uni chaqirayotganingizni tekshiring.
8. Mashqlar
1-mashq (oson): Stekni chizing
console.log bajarilayotgan paytda stekda qaysi kontekstlar bor? Pastdan tepaga yozing.
function sabziTogra() {
console.log("Sabzi to'g'ralmoqda");
}
function sabzavotTayyorla() {
sabziTogra();
}
function oshPishir() {
sabzavotTayyorla();
}
oshPishir();Yechim
Pastdan tepaga: global → oshPishir() → sabzavotTayyorla() → sabziTogra(). To'rt kontekst. sabziTogra tepada — u bajarilmoqda, qolgan uchtasi uni kutyapti. Tekshirish uchun console.log o'rniga console.trace() yozing (console API) — Node har kontekstni at qatori bilan chiqaradi.
2-mashq (o'rta): Tartibni oldindan ayting
Kodni ishga tushirmasdan, konsolda nima va qaysi tartibda chiqishini yozing. Keyin tekshiring.
function choyQuy() {
console.log("2. Choy quyildi");
}
function stolgaOlibBor() {
console.log("1. Patnis olindi");
choyQuy();
console.log("3. Stolga qo'yildi");
}
console.log("0. Buyurtma keldi");
stolgaOlibBor();
console.log("4. Tayyor");Yechim
Konsolda:
0. Buyurtma keldi
1. Patnis olindi
2. Choy quyildi
3. Stolga qo'yildi
4. TayyorstolgaOlibBor 7-qatorda choyQuy ni chaqirdi va to'xtab turdi. choyQuy konteksti tugagach, stolgaOlibBor aynan to'xtagan joyidan — 8-qatordan — davom etdi. "3" faqat "2" dan keyin chiqadi: stekda tepadagi tugamaguncha, pastdagisi davom etmaydi.
3-mashq (qiyin): Ikki funksiyali rekursiya
juftmi(n) va toqmi(n) funksiyalarini yozing. % ishlatmang — ular bir-birini chaqirsin: juftmi(0) — true, toqmi(0) — false, aks holda juftmi(n) = toqmi(n - 1) va aksincha. Stekning eng katta chuqurligini sanang: global o'zgaruvchi chuqurlik har kontekst boshida bittaga oshsin, tugashidan oldin kamaysin; eng kattasi eng da saqlansin.
Yechim
let chuqurlik = 0;
let eng = 0;
function kirdi() {
chuqurlik++;
eng = Math.max(eng, chuqurlik);
}
function juftmi(n) {
kirdi();
const javob = n === 0 ? true : toqmi(n - 1);
chuqurlik--;
return javob;
}
function toqmi(n) {
kirdi();
const javob = n === 0 ? false : juftmi(n - 1);
chuqurlik--;
return javob;
}
console.log(juftmi(4)); // true
console.log(eng); // 5
console.log(toqmi(3)); // true
console.log(chuqurlik); // 0juftmi(4) → toqmi(3) → juftmi(2) → toqmi(1) → juftmi(0): stekda bir vaqtda 5 ta kontekst (global'siz). Oxirida chuqurlik yana 0 — har kirgan kontekst chiqib ketdi. kirdi ning o'z konteksti ham bir lahzaga yaratiladi, lekin u darhol tugaydi — biz faqat juftmi/toqmi larni sanadik. juftmi(-1) chaqirsangiz — n hech qachon 0 bo'lmaydi va RangeError: Maximum call stack size exceeded.
4-mashq: Vazifalar qadami — bitta bosishning yo'li
Bu darsda vazifalar kodini o'zgartirmaymiz — uning ichiga qaraymiz. Natijani mashqlar repoga yozasiz: kurs/mashqlar/10/19-call-stack/javoblar.md.
vazifalarni Live Server'da oching, DevTools → Sources,vazifalar.js.statistikafunksiyasining birinchi qatoriga (const guruhlar = Object.groupBy() breakpoint qo'ying. Sahifani yangilang — u darhol to'xtaydi. Call Stack ni yozing. F8 bilan davom ettiring.- "Non olish" katagini bosing — yana to'xtaydi. Call Stack'ni yozing.
- Yangi vazifa qo'shing va «Faol» filtrini bosing — har birida Call Stack'ni yozing.
- Savol: to'rt holatda qaysi ikki qator doim bir xil? Bu nimani bildiradi?
Yechim
javoblar.md (Chrome'da, tepadan pastga — DevTools tepadagi kontekstni birinchi ko'rsatadi):
Sahifa ochilganda: statistika ← render ← (anonymous)
Katakni bosganda: statistika ← render ← vazifaniAlmashtir ← (anonymous)
Vazifa qo'shganda: statistika ← render ← vazifaQosh ← (anonymous)
Filtrni bosganda: statistika ← render ← filtrniTanla ← (anonymous)Eng pastdagi (anonymous): sahifa ochilganda — skriptning o'zi (global kontekst), qolganlarida — nomsiz arrow funksiya, ya'ni hodisa tinglovchisi.
Tepadagi ikkitasi — statistika va render — doim bir xil. Demak ilova holatni qanday o'zgartirmasin, ekran bitta yo'l bilan — render() orqali — yangilanadi. Bu Holatdan UI chizish qolipining isboti: "holatni o'zgartir → render()". Uchinchi qator esa holatni aynan kim o'zgartirganini ko'rsatadi.
Qo'shimcha: katakni bosgandagi Call Stack'da vazifaniAlmashtir qatorini bosing. Scope bo'limida o'sha kontekstning id parametri ko'rinadi — siz bosgan vazifaning raqami. Har stek qavati — o'z o'zgaruvchilari bilan alohida kontekst.
Breakpoint'ni olib tashlang. Commit — mashqlar repoda:
git add 10/19-call-stack/javoblar.md
git commit -m "10/19: vazifalar call stack'ini yoz"9. Real ishda
- Debug. Xato loglari (Sentry kabi xizmatlar) foydalanuvchidagi xatoni stack trace bilan yuboradi. Uni kontekstlar ro'yxati sifatida o'qiy olgan dasturchi xatoni ancha tez topadi.
- Performans. Brauzer DevTools'ining Performance paneli vaqt bo'yicha call stack'ni chizadi ("flame chart"). Qaysi funksiya stekni uzoq band qilganini shu yerda ko'rasiz — sahifa nega qotayotganini topishning asosiy usuli.
- Intervyu. "Execution context nima?", "Call stack qanday ishlaydi?", "JavaScript nega bir oqimli?" — boshlang'ich (junior) va o'rta (middle) darajali dasturchi intervyularida juda ko'p beriladi. Keyingi savol odatda hoisting va closure haqida bo'ladi — ular ham shu mavzuning davomi.
Xulosa
- Execution context — bajarilayotgan kod uchun ichki yozuv: o'zgaruvchilar, tashqi havola,
this. - Global kontekst bitta; funksiya konteksti har chaqiruvda yangisi yaratiladi. E'lon kontekst yaratmaydi.
- Har kontekst ikki bosqichdan o'tadi: yaratish (e'lonlar ro'yxatga) va bajarish (qatorma-qator).
- Call stack — kontekstlar taxlami: chaqiruv — tepaga qo'yish,
return— olib tashlash. - Stack trace — xato paytidagi stek surati;
atqatorlari — kontekstlar, pastdan tepaga o'sgan. - Stek bitta — bir vaqtda bitta ish bajariladi.
Keyingi dars: Leksik scope va scope zanjiri — kontekstning ikkinchi qismi, "tashqi havola"ni ochamiz: topilmagan nom qayerdan va qaysi tartibda qidiriladi.
Manbalar
- ECMAScript 2025 Language Specification: "Execution Contexts", "Execution Context Stack" — tc39.es/ecma262
- MDN: "Call stack" (Glossary), "JavaScript execution model" — developer.mozilla.org
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!