Amaliy misollar orqali JavaScript yopilmalarini (closures) o'rganing, ularning qanday ishlashini va dasturiy ta'minotni ishlab chiqishda real hayotdagi qo'llanilishini tushuning.
JavaScript Yopilmalari (Closures): Amaliy Misollar Bilan Tushuntirish
Yopilmalar (closures) JavaScript-dagi fundamental tushuncha bo'lib, ko'pincha barcha darajadagi dasturchilarda chalkashliklarga sabab bo'ladi. Samarali, qo'llab-quvvatlanadigan va xavfsiz kod yozish uchun yopilmalarni tushunish juda muhimdir. Ushbu keng qamrovli qo'llanma amaliy misollar bilan yopilmalarni tushuntiradi va ularning real hayotdagi qo'llanilishini namoyish etadi.
Yopilma (Closure) nima?
Oddiy qilib aytganda, yopilma - bu funksiya va ushbu funksiya e'lon qilingan leksik muhitning birikmasidir. Bu shuni anglatadiki, yopilma funksiyaga tashqi funksiya o'z ishini tugatgandan keyin ham o'zining atrofidagi ko'lamdan (scope) o'zgaruvchilarga kirish imkonini beradi. Buni ichki funksiyaning o'z muhitini "eslab qolishi" deb tasavvur qiling.
Buni to'liq tushunish uchun asosiy tarkibiy qismlarni ko'rib chiqaylik:
- Funksiya: Yopilmaning bir qismini tashkil etuvchi ichki funksiya.
- Leksik Muhit: Funksiya e'lon qilingan atrofdagi ko'lam (scope). Bunga o'zgaruvchilar, funksiyalar va boshqa e'lonlar kiradi.
Sehr shundaki, ichki funksiya tashqi funksiya qaytarilgandan keyin ham o'zining leksik ko'lamidagi o'zgaruvchilarga kirish huquqini saqlab qoladi. Bu xususiyat JavaScript-ning ko'lam (scope) va xotirani boshqarish usulining asosiy qismidir.
Nima uchun Yopilmalar Muhim?
Yopilmalar shunchaki nazariy tushuncha emas; ular JavaScript-dagi ko'plab keng tarqalgan dasturlash na'munalari uchun zarurdir. Ular quyidagi afzalliklarni taqdim etadi:
- Ma'lumotlar inkapsulyatsiyasi: Yopilmalar sizga shaxsiy (private) o'zgaruvchilar va metodlarni yaratishga imkon beradi, bu esa ma'lumotlarni tashqi kirish va o'zgartirishdan himoya qiladi.
- Holatni Saqlash: Yopilmalar funksiya chaqiruvlari o'rtasida o'zgaruvchilarning holatini saqlab qoladi, bu esa hisoblagichlar, taymerlar va boshqa holatga ega komponentlarni yaratish uchun foydalidir.
- Yuqori Tartibli Funksiyalar: Yopilmalar ko'pincha yuqori tartibli funksiyalar (boshqa funksiyalarni argument sifatida qabul qiladigan yoki funksiyalarni qaytaradigan funksiyalar) bilan birgalikda ishlatilib, kuchli va moslashuvchan kod yozish imkonini beradi.
- Asinxron JavaScript: Yopilmalar qayta chaqiruvlar (callbacks) va va'dalar (promises) kabi asinxron operatsiyalarni boshqarishda muhim rol o'ynaydi.
JavaScript Yopilmalarining Amaliy Misollari
Keling, yopilmalarning qanday ishlashini va ularni real hayot stsenariylarida qanday qo'llash mumkinligini ko'rsatish uchun ba'zi amaliy misollarga sho'ng'iymiz.
1-misol: Oddiy Hisoblagich
Ushbu misol funksiya chaqiruvlari o'rtasida o'z holatini saqlaydigan hisoblagichni yaratish uchun yopilmadan qanday foydalanish mumkinligini ko'rsatadi.
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const increment = createCounter();
increment(); // Natija: 1
increment(); // Natija: 2
increment(); // Natija: 3
Tushuntirish:
createCounter()
- bucount
o'zgaruvchisini e'lon qiladigan tashqi funksiya.- U
count
o'zgaruvchisini birga oshiradigan va uning qiymatini konsolga chiqaradigan ichki funksiyani (bu holda anonim funksiya) qaytaradi. - Ichki funksiya
count
o'zgaruvchisi ustida yopilma hosil qiladi. createCounter()
o'z ishini tugatgandan keyin ham ichki funksiyacount
o'zgaruvchisiga kirish huquqini saqlab qoladi.increment()
ga har bir chaqiruv bir xilcount
o'zgaruvchisini oshiradi, bu esa yopilmaning holatni saqlash qobiliyatini namoyish etadi.
2-misol: Shaxsiy O'zgaruvchilar Bilan Ma'lumotlar Inkapsulyatsiyasi
Yopilmalar shaxsiy (private) o'zgaruvchilar yaratish uchun ishlatilishi mumkin, bu ma'lumotlarni funksiya tashqarisidan to'g'ridan-to'g'ri kirish va o'zgartirishdan himoya qiladi.
function createBankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit: function(amount) {
balance += amount;
return balance; //Namoyish uchun qaytarilmoqda, void bo'lishi mumkin edi
},
withdraw: function(amount) {
if (amount <= balance) {
balance -= amount;
return balance; //Namoyish uchun qaytarilmoqda, void bo'lishi mumkin edi
} else {
return "Mablag' yetarli emas.";
}
},
getBalance: function() {
return balance;
}
};
}
const account = createBankAccount(1000);
console.log(account.deposit(500)); // Natija: 1500
console.log(account.withdraw(200)); // Natija: 1300
console.log(account.getBalance()); // Natija: 1300
// Balansga to'g'ridan-to'g'ri kirishga urinish ishlamaydi
// console.log(account.balance); // Natija: undefined
Tushuntirish:
createBankAccount()
pul qo'yish, yechib olish va balansni olish metodlari bilan bank hisobi obyektini yaratadi.balance
o'zgaruvchisicreateBankAccount()
ko'lami ichida e'lon qilingan va tashqaridan to'g'ridan-to'g'ri kirish imkoni yo'q.deposit
,withdraw
, vagetBalance
metodlaribalance
o'zgaruvchisi ustida yopilmalar hosil qiladi.- Bu metodlar
balance
o'zgaruvchisiga kira oladi va uni o'zgartira oladi, lekin o'zgaruvchining o'zi shaxsiy bo'lib qoladi.
3-misol: Siklda `setTimeout` Bilan Yopilmalardan Foydalanish
Yopilmalar asinxron operatsiyalar, masalan, setTimeout
bilan ishlashda, ayniqsa sikllar ichida juda muhimdir. Yopilmalarsiz, JavaScript-ning asinxron tabiati tufayli kutilmagan xatti-harakatlarga duch kelishingiz mumkin.
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function() {
console.log("i ning qiymati: " + j);
}, j * 1000);
})(i);
}
// Natija:
// i ning qiymati: 1 (1 soniyadan keyin)
// i ning qiymati: 2 (2 soniyadan keyin)
// i ning qiymati: 3 (3 soniyadan keyin)
// i ning qiymati: 4 (4 soniyadan keyin)
// i ning qiymati: 5 (5 soniyadan keyin)
Tushuntirish:
- Yopilmasiz (darhol chaqiriladigan funksiya ifodasi yoki IIFE), barcha
setTimeout
qayta chaqiruvlari oxir-oqibat bir xili
o'zgaruvchisiga murojaat qilgan bo'lar edi, u esa sikl tugagandan so'ng 6 ga teng bo'lib qolardi. - IIFE siklning har bir iteratsiyasi uchun yangi ko'lam yaratadi va
i
ning joriy qiymatinij
parametrida saqlab qoladi. - Har bir
setTimeout
qayta chaqiruvij
o'zgaruvchisi ustida yopilma hosil qiladi, bu esa har bir iteratsiya uchuni
ning to'g'ri qiymatini konsolga chiqarishni ta'minlaydi.
Siklda var
o'rniga let
dan foydalanish ham bu muammoni hal qiladi, chunki let
har bir iteratsiya uchun blokli ko'lam (block scope) yaratadi.
for (let i = 1; i <= 5; i++) {
setTimeout(function() {
console.log("i ning qiymati: " + i);
}, i * 1000);
}
// Natija (yuqoridagi bilan bir xil):
// i ning qiymati: 1 (1 soniyadan keyin)
// i ning qiymati: 2 (2 soniyadan keyin)
// i ning qiymati: 3 (3 soniyadan keyin)
// i ning qiymati: 4 (4 soniyadan keyin)
// i ning qiymati: 5 (5 soniyadan keyin)
4-misol: Karring (Currying) va Qisman Qo'llash (Partial Application)
Yopilmalar ko'p argumentli funksiyalarni har biri bitta argument qabul qiladigan funksiyalar ketma-ketligiga aylantirish uchun ishlatiladigan karring va qisman qo'llash texnikalari uchun asosiy hisoblanadi.
function multiply(a) {
return function(b) {
return function(c) {
return a * b * c;
};
};
}
const multiplyBy5 = multiply(5);
const multiplyBy5And2 = multiplyBy5(2);
console.log(multiplyBy5And2(3)); // Natija: 30 (5 * 2 * 3)
Tushuntirish:
multiply
- bu uchta argumentni birma-bir qabul qiladigan karring funksiyasi.- Har bir ichki funksiya o'zining tashqi ko'lamidagi o'zgaruvchilar (
a
,b
) ustida yopilma hosil qiladi. multiplyBy5
- bua
o'zgaruvchisi allaqachon 5 ga tenglashtirilgan funksiya.multiplyBy5And2
- bua
5 ga vab
2 ga tenglashtirilgan funksiya.multiplyBy5And2(3)
ga oxirgi chaqiruv hisob-kitobni yakunlaydi va natijani qaytaradi.
5-misol: Modul Namunasi (Module Pattern)
Yopilmalar modul namunasida keng qo'llaniladi, bu JavaScript kodini tashkil etish va tuzilishga yordam beradi, modullikni oshiradi va nomlar to'qnashuvining oldini oladi.
const myModule = (function() {
let privateVariable = "Salom, dunyo!";
function privateMethod() {
console.log(privateVariable);
}
return {
publicMethod: function() {
privateMethod();
},
publicProperty: "Bu ommaviy xususiyat."
};
})();
console.log(myModule.publicProperty); // Natija: Bu ommaviy xususiyat.
myModule.publicMethod(); // Natija: Salom, dunyo!
// privateVariable yoki privateMethod'ga to'g'ridan-to'g'ri kirishga urinish ishlamaydi
// console.log(myModule.privateVariable); // Natija: undefined
// myModule.privateMethod(); // Natija: TypeError: myModule.privateMethod funksiya emas
Tushuntirish:
- IIFE yangi ko'lam yaratib,
privateVariable
vaprivateMethod
'ni inkapsulyatsiya qiladi. - Qaytarilgan obyekt faqat
publicMethod
vapublicProperty
'ni ochiq qiladi. publicMethod
privateMethod
vaprivateVariable
ustida yopilma hosil qiladi, bu esa IIFE bajarilgandan keyin ham ularga kirish imkonini beradi.- Bu namuna shaxsiy va ommaviy a'zolarga ega modulni samarali yaratadi.
Yopilmalar va Xotirani Boshqarish
Yopilmalar kuchli bo'lsa-da, ularning xotirani boshqarishga potentsial ta'siridan xabardor bo'lish muhimdir. Yopilmalar o'zlarining atrofidagi ko'lamdan o'zgaruvchilarga kirish huquqini saqlab qolganligi sababli, agar bu o'zgaruvchilar endi kerak bo'lmasa, ularning axlat yig'uvchi (garbage collector) tomonidan tozalanishiga to'sqinlik qilishi mumkin. Agar ehtiyotkorlik bilan ishlanmasa, bu xotira oqishiga (memory leaks) olib kelishi mumkin.
Xotira oqishini oldini olish uchun, yopilmalar ichidagi o'zgaruvchilarga keraksiz havolalarni ular endi kerak bo'lmaganda uzishga ishonch hosil qiling. Buni o'zgaruvchilarni null
ga tenglashtirish yoki keraksiz yopilmalar yaratishdan qochish uchun kodingizni qayta tuzish orqali amalga oshirish mumkin.
Yopilmalar Bilan Bog'liq Keng Tarqalgan Xatolardan Qochish
- Leksik Ko'lamni Unutish: Har doim yodda tutingki, yopilma muhitni *yaratilish vaqtida* o'ziga oladi. Agar yopilma yaratilgandan keyin o'zgaruvchilar o'zgarsa, yopilma ushbu o'zgarishlarni aks ettiradi.
- Keraksiz Yopilmalar Yaratish: Agar kerak bo'lmasa, yopilmalar yaratishdan saqlaning, chunki ular samaradorlik va xotiradan foydalanishga ta'sir qilishi mumkin.
- O'zgaruvchilar Oqishi: Yopilmalar tomonidan olingan o'zgaruvchilarning yashash muddati haqida ehtiyot bo'ling va xotira oqishini oldini olish uchun ular endi kerak bo'lmaganda bo'shatilishini ta'minlang.
Xulosa
JavaScript yopilmalari har bir JavaScript dasturchisi tushunishi kerak bo'lgan kuchli va muhim tushunchadir. Ular ma'lumotlar inkapsulyatsiyasi, holatni saqlash, yuqori tartibli funksiyalar va asinxron dasturlash imkonini beradi. Yopilmalarning qanday ishlashini va ulardan samarali foydalanishni tushunish orqali siz yanada samarali, qo'llab-quvvatlanadigan va xavfsiz kod yozishingiz mumkin.
Ushbu qo'llanma amaliy misollar bilan yopilmalarning keng qamrovli sharhini taqdim etdi. Ushbu misollar bilan mashq qilib va tajriba o'tkazib, siz yopilmalar haqidagi tushunchangizni chuqurlashtirishingiz va yanada malakali JavaScript dasturchisiga aylanishingiz mumkin.
Qo'shimcha O'rganish Uchun
- Mozilla Developer Network (MDN): Yopilmalar - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
- Kyle Simpsonning "You Don't Know JS: Scope & Closures" kitobi
- Turli yopilma misollari bilan tajriba o'tkazish uchun CodePen va JSFiddle kabi onlayn kodlash platformalarini o'rganing.