O'zgaruvchi ko'lami, closure
JavaScript funksiyalar tili sanaladi. Bu unga katta moslashuvchanlik beradi: funksiyalarni yaratish, o'zgaruvchiga berish, boshqa funksiyaga uzatish va keyinroq chaqirish mumkin. Buni tushunish uchun o'zgaruvchi ko'lami va closure tushunchalarini o'rganamiz.
Blok ko'lami (block scope)
let va const orqali e'lon qilingan o'zgaruvchi faqat o'zi joylashgan blok ichida (figurali qavslar { } orasida) ko'rinadi. Blokdan tashqarida u mavjud emas:
Xuddi shunday, if, for, while bloklari ham o'z ko'lamiga ega. for siklidagi hisoblagich i faqat sikl ichida yashaydi:
Ichki funksiyalar va tashqi o'zgaruvchilar
Funksiya ichida boshqa funksiya (ichki, nested funksiya) e'lon qilinishi mumkin. Eng muhimi โ ichki funksiya tashqi funksiyaning o'zgaruvchilariga kira oladi:
Ichki funksiya tashqi o'zgaruvchini nafaqat o'qishi, balki o'zgartirishi ham mumkin. Bu oddiy ko'rinsa-da, closure'ning asosini tashkil etadi.
Leksik muhit (lexical environment) โ soddalashtirib
JavaScript ichkarida o'zgaruvchilarni qanday izlaydi? Buni tushunish uchun leksik muhit tushunchasi kerak. Uni soddalashtirib shunday tasavvur qiling:
- Har bir ishlayotgan blok, funksiya va butun skript uchun ichkarida maxsus Leksik Muhit obyekti bor;
- Bu obyektda o'sha joydagi barcha lokal o'zgaruvchilar saqlanadi;
- Har bir muhit o'zining tashqi (ota) muhitiga ishora qiladi.
O'zgaruvchi ishlatilganda, JavaScript uni avval joriy muhitdan qidiradi. Topmasa โ tashqi muhitga chiqadi, u yerdan ham topmasa yana tashqariga... shu tariqa eng tashqi (global) muhitga qadar. Bu "tashqariga qarab qidirish" zanjiri closure'ning kalitidir.
Closure nima?
Closure (yopilma) โ bu tashqi o'zgaruvchilarni eslab qoladigan va ularga kira oladigan funksiya. JavaScript'da deyarli barcha funksiyalar closure hisoblanadi โ ular yaratilgan joydagi tashqi o'zgaruvchilarni "eslab qoladi".
Sehr shundaki: tashqi funksiya ishlab bo'lgach ham, uning o'zgaruvchilari yo'qolmaydi โ agar ularga ichki funksiya hali ham ishora qilib turgan bo'lsa. Quyidagi misolda buni ko'ramiz:
makeGreeter('Ali') chaqiruvi tugagan bo'lsa ham, qaytarilgan funksiya o'zining name = 'Ali' qiymatini eslab turadi. greetAli va greetVali โ bir-biridan mustaqil, chunki har biri o'z leksik muhitini saqlaydi.
Hisoblagich (counter) misoli
Closure'ning eng klassik va foydali misoli โ hisoblagich. Har chaqirilganda keyingi sonni qaytaruvchi funksiya yasaymiz. Hisob count tashqarida yashiringan, unga faqat qaytarilgan funksiya orqali kirish mumkin:
Har chaqiruvda count qiymati saqlanib, ortib boradi. Bu shuni ko'rsatadiki, count o'zgaruvchisi bitta va o'sha โ funksiya uni haqiqatan eslab turibdi, har safar noldan boshlamaydi.
Har bir makeCounter() chaqiruvi esa butunlay yangi, mustaqil hisoblagich yaratadi:
Amaliy foyda
Closure nazariya emas โ u har kuni ishlatiladigan amaliy vosita:
- Ma'lumotni yashirish โ
countkabi o'zgaruvchini tashqi dunyodan berkitib, faqat ma'lum funksiyalar orqali boshqarish (inkapsulyatsiya); - Holatni saqlash โ hisoblagichlar, ID generatorlari, keshlash;
- Callback va hodisa ishlovchilari โ tugma bosilganda ishlaydigan funksiya o'zi yaratilgan paytdagi ma'lumotni eslaydi;
- Funksiya fabrikalari โ
makeGreeterkabi, sozlangan yangi funksiyalar yasash.
Sozlanadigan funksiya fabrikasi misoli โ berilgan koeffitsientga ko'paytiruvchi funksiyalar yasaymiz:
Xulosa
let/consto'zgaruvchilari blok ko'lamiga ega โ faqat{ }ichida yashaydi;- Ichki funksiya tashqi funksiyaning o'zgaruvchilariga kira oladi;
- O'zgaruvchi qidiruvi ichkaridan tashqariga leksik muhit zanjiri bo'ylab boradi; bog'lanish kod yozilgan joyga qarab aniqlanadi;
- Closure โ tashqi o'zgaruvchilarni eslab qoladigan funksiya; tashqi funksiya tugasa ham ular saqlanadi;
- Closure ma'lumotni yashirish, holatni saqlash va funksiya fabrikalari uchun ishlatiladi (masalan hisoblagich).