JavaScript'da Closure tushunchasi, leksik muhitni eslab qolish mexanizmi, xususiy (private) o'zgaruvchilar, loop ichida closure, IIFE va function factory namunalari.
Closure — JavaScript'dagi eng kuchli, ayni paytda eng qiyin tushuniladigan mavzulardan biri. Aslida, agar Chapter 11 (Scope Chain)ni tushungan bo'lsangiz, Closure sizga unchalik qiyin tuyulmaydi — chunki Closure aynan Scope Chain'ning tabiiy natijasidir.
Closure — function o'zi yaratilgan muhitdagi (scope'dagi) variable'larni "eslab qolishi" va o'sha function boshqa joyda chaqirilganda ham o'sha variable'larga murojaat qila olishi.
Closure orqali:
🎒 Closure'ni "sayohatga olib ketiladigan ryukzak" deb tasavvur qiling. Function tug'ilgan joyidan (scope'idan) uzoqlashsa ham, o'sha yerdagi kerakli narsalarni (variable'larni) ryukzagiga solib, o'zi bilan olib ketadi.
script.jsJavaScriptfunction outer() {let message = "Salom, Closure!";function inner() {console.log(message);}return inner;}let myFunction = outer();myFunction(); // "Salom, Closure!"
Bu — ko'pchilikni chalg'itadigan joy, shuning uchun batafsil ko'ramiz:
outer() chaqiriladi.outer() ichida message variable yaratiladi va inner nomli function e'lon qilinadi.outer() — inner functionning o'zini (chaqirmasdan) return qiladi.outer() ishlashi tugagach, uning ichidagi message variable "yo'qolishi" kerak edi (chunki function scope tugadi).inner function messagega bog'liq bo'lgani uchun, JavaScript engine messageni xotiradan o'chirmaydi, balki inner bilan birga "saqlab qoladi".myFunction — aslida inner functionning o'zi, va u hali ham messagega kira oladi, garchi outer() allaqachon "tugagan" bo'lsa ham.code.textTEXTouter() chaqiriladi│├── message = "Salom, Closure!" yaratiladi│└── inner function yaratiladi (message'ni "eslab qoladi")│└── return inner → outer() tugaydi, LEKINmessage o'chmaydi, chunkiinner unga hali ham bog'liq
🔥 Important
Bu — Closure'ning eng muhim va eng "sehrli" tomoni: odatda function tugagach uning ichidagi local variable'lar xotiradan tozalanadi (garbage collection), lekin agar ichki function tashqi variable'ga bog'liq bo'lib qolsa, o'sha variable "tirik" qolaveradi.
Closure'ning eng ko'p ishlatiladigan qo'llanilishi — private (tashqaridan bevosita o'zgartirib bo'lmaydigan) ma'lumot yaratish.
script.jsJavaScriptfunction createCounter() {let count = 0;return {increment: function () {count++;return count;},decrement: function () {count--;return count;},getCount: function () {return count;}};}let counter = createCounter();console.log(counter.increment()); // 1console.log(counter.increment()); // 2console.log(counter.decrement()); // 1console.log(counter.count); // undefined — to'g'ridan-to'g'ri kirib bo'lmaydi!
count variable createCounter() ichida "yashiringan". Uni faqat increment, decrement, getCount orqaligina o'zgartirish yoki ko'rish mumkin — to'g'ridan-to'g'ri counter.count deb yozib bo'lmaydi.
💡 Key Idea
Bu — boshqa dasturlash tillaridagi encapsulation (Chapter 24'da OOP orqali ham o'rganamiz) tushunchasining Closure yordamida amalga oshirilishi.
Bu — Chapter 11'da ko'rgan var muammosining Closure nuqtai nazaridan tushuntirilishi. Endi buni chuqurroq ko'ramiz.
script.jsJavaScriptfunction createFunctions() {let functions = [];for (var i = 1; i <= 3; i++) {functions.push(function () {console.log(i);});}return functions;}let funcs = createFunctions();funcs[0](); // 4funcs[1](); // 4funcs[2](); // 4
Bu yerda 3 ta alohida function yaratilganday tuyuladi, lekin aslida ularning barchasi bitta xuddi shu i variable'ga closure orqali bog'langan (chunki var — function scope, u loop uchun alohida nusxa yaratmaydi).
Loop tugagach, i qiymati 4 bo'lib qoladi (chunki i <= 3 sharti false bo'lganda i allaqachon 4ga teng bo'ladi), va barcha 3 ta function xuddi shu ini "ko'radi".
code.textTEXTi (bitta, umumiy) = 4 (loop tugagandan keyin)↑ ↑ ↑funcs[0] funcs[1] funcs[2](barchasi bitta i ga ishora qiladi)
script.jsJavaScriptfor (let i = 1; i <= 3; i++) {functions.push(function () {console.log(i);});}// Natija: 1, 2, 3
Nima uchun ishlaydi? let — har bir iteratsiyada yangi i yaratadi (Chapter 11, block scope). Shuning uchun har bir function o'zining alohida i nusxasiga closure orqali bog'lanadi.
code.textTEXTi=1 (o'z nusxasi) ← funcs[0]i=2 (o'z nusxasi) ← funcs[1]i=3 (o'z nusxasi) ← funcs[2]
script.jsJavaScriptfor (var i = 1; i <= 3; i++) {(function (currentI) {functions.push(function () {console.log(currentI);});})(i);}
Har bir iteratsiyada darhol chaqiriladigan function (IIFE — Immediately Invoked Function Expression) yaratiladi, va u ining joriy qiymatini currentI parametriga nusxalab oladi — shu orqali har bir iteratsiya uchun alohida "muzlatilgan" qiymat hosil bo'ladi.
🔗 Connection
Bugungi kunda let mavjud bo'lgani uchun, IIFE usuli kamdan-kam ishlatiladi, lekin eski kodlarni tushunish uchun buni bilish muhim.
Closure orqali "sozlangan" function'lar yaratuvchi function'lar (function factory) yasash mumkin.
script.jsJavaScriptfunction createMultiplier(multiplier) {return function (number) {return number * multiplier;};}let double = createMultiplier(2);let triple = createMultiplier(3);console.log(double(5)); // 10console.log(triple(5)); // 15
double va triple — ikkalasi ham createMultiplierdan yaratilgan, lekin har biri o'zining multiplier qiymatini (mos ravishda 2 va 3) closure orqali "eslab qoladi".
🎯 Bu naqsh — dasturlashda "partial application" yoki **"currying"**ning oddiy shakli hisoblanadi (Chapter 45'da chuqurroq o'rganamiz).
Task:
greet(name) function qaytaradigan createGreeter() function yozing — natijada name parametrini "eslab qolgan" yangi function hosil bo'lsin.
Required Concepts:
createGreeter() ichida function qaytaring, u nameni parametr sifatida qabul qilsin.Task:
createCounter() funksiyasini kengaytirib, unga reset() metodini qo'shing — bu metod countni 0ga qaytarsin.
Required Concepts:
return qilinayotgan object ichiga yana bitta method qo'shing.Task:
Bank hisobini simulyatsiya qiluvchi closure yozing: balance — private bo'lsin, faqat deposit(amount), withdraw(amount), getBalance() orqali unga ta'sir qilish mumkin bo'lsin. withdraw — agar balansdan ko'p pul yechilsa, xatolik xabarini chiqarsin.
Required Concepts:
withdraw ichida if (amount > balance) shartini tekshiring.script.jsJavaScriptfunction outer() {let count = 0;return function () {count++;return count;};}let counter1 = outer();let counter2 = outer();console.log(counter1()); // ?console.log(counter1()); // ?console.log(counter2()); // ?
🧠 Think first! Javobni ko'rishdan oldin kamida 30 soniya o'ylang.
<details> <summary>Answer</summary> 1 2 1Why?
counter1 va counter2 — ikkalasi ham outer()ning alohida chaqiruvidan yaratilgan, shuning uchun har biri o'zining alohida count nusxasiga ega. counter1ni chaqirish counter2ning countiga ta'sir qilmaydi.
Quyidagi kodda muammo bor:
script.jsJavaScriptfunction createButtons() {for (var i = 1; i <= 3; i++) {document.body.innerHTML += `<button onclick="console.log(${i})">Button</button>`;}}
Dasturchi 3 ta tugma yaratmoqchi: birinchisi 1, ikkinchisi 2, uchinchisi 3 chiqarishi kerak. Lekin barcha tugmalar bosilganda faqat oxirgi qiymat chiqadi (agar closure orqali yozilganda edi).
Your Task:
addEventListener bilan) yozilganda, qanday muammo yuzaga kelishini tushuntiring.varni letga almashtirib, closure asosidagi to'g'ri yechim yozing.script.jsJavaScript// ❌ Muammoli versiyafor (var i = 1; i <= 3; i++) {button.addEventListener("click", function () {console.log(i);});}
Barcha tugmalar 4ni chiqargan bo'lardi, chunki barcha click handler'lar bitta umumiy iga bog'langan bo'lardi.
Yechim:
script.jsJavaScript// ✅ To'g'ri versiyafor (let i = 1; i <= 3; i++) {button.addEventListener("click", function () {console.log(i);});}
let har bir iteratsiya uchun alohida i yaratadi, shuning uchun har bir tugma o'zining closure orqali "eslab qolingan" qiymatini chiqaradi.
var bilan closure ishlatilsa, barcha function'lar bitta umumiy variable'ga bog'lanadi.let — har bir iteratsiyada yangi scope yaratib, bu muammoni hal qiladi.outer()) o'zining alohida closure muhitini yaratadi.var — klassik xato manbai, let bilan hal qilinadi.script.jsJavaScriptfunction outer() {let secret = "hidden";return function () {return secret; // closure orqali secret'ga kirish};}let getSecret = outer();console.log(getSecret()); // "hidden"// Private counter patternfunction createCounter() {let count = 0;return {increment: () => ++count,getCount: () => count};}
Mavzu bo‘yicha tushunchalaringizni interaktiv test orqali sinovdan o‘tkazing va natijalarni bilib oling.
Darslikda o‘rganilgan qoidalarga asosan real kod yozing, testlardan o‘tkazing va yechimlarni mustahkamlang.
Test Sinovi
Hali topshirilmagan (kamida 75% kerak)
Amaliy Masalalar
0 / 3 ta yechildi (kamida 75% kerak)
Dars sifati va mazmunini yaxshilash uchun o‘z haqqoniy bahoingizni qoldiring.
Mavzuni to‘liq o‘zlashtirish uchun test sinovi, amaliy kodlash va bog‘liq darslar
O‘z bilimingizni interaktiv test savollari orqali tekshiring va darhol xatolarni tahlil qiling.
Nazariyani real kod yozish bilan mustahkamlang, avtomatik testlardan o‘ting va XP to‘plang.
Kurs bo‘yicha keyingi va bog‘liq mavzular: