javascript
July 13, 2025

JavaScript’da Lexical Environment (Scoping) va Closure

JavaScript — kuchli, ammo ba’zan murakkab til. Ayniqsa, closure va lexical scope kabi tushunchalar ko‘pchilikni chalkashtirib yuboradi. Ushbu maqolada siz bu tushunchalarni nafaqat nazariy, balki amaliy misollar orqali ham chuqur tushunib olasiz.

Bu maqolada siz quyidagilarni o'rganasiz :

  • Lexical Environment nima?
  • Scope turlari (Global, Function, Block)
  • Closure nima va qanday ishlaydi?
  • 5 ta amaliy misollar bilan mustahkamlash.

1. Lexical Environment nima?

Har bir JavaScript funksiyasi ishlayotganida o‘zining lexical environmentiga ega bo‘ladi. Bu environment 2 ta asosiy qismdan iborat:

  • Environment Record – o‘zgaruvchilar va funksiyalar haqida ma’lumot saqlanadigan qism.
  • Outer Lexical Environment Reference – tashqi (ya’ni yuqoridagi) scope’ga bog‘lanadi.

JavaScript’da bu struktura chain-like scope resolution ni tashkil qiladi.

2. Scoping turlari

Scope - o’zgaruvchi va funksiyalar qayerda ko’rinish/ko’rinmasligini aniqlab beruvchi tushuncha.

Global - Har joyda mavjud
Function - Faqat funksiyada ko‘rinadi
Block - {} ichida (let, const o'zgaruvchilar bunga misol)

Misol 1: Global va Function scope

var globalVar = "I'm global";

function example() {
  let localVar = "I'm local";
  console.log(globalVar); // "I'm global"
  console.log(localVar);  // "I'm local"
}

example();
// console.log(localVar); // ReferenceError: localVar is not defined
Bu yerda localVar faqat example funksiyasi ichida mavjud. Tashqarida unga murojaat qilib bo‘lmaydi

Misol 2: Block scope ( var, let, const)

function blockScopeExample() {
  if (true) {
    let a = 42;
    const b = 100;
    var c = 123
    console.log(a, b); // 42 100
  }
  // console.log(a); // ReferenceError
  // console.log(b); // ReferenceError
  // console.log(c); // 123

}

blockScopeExample();
let va const {} block-scoped bo'lganligi uchun u yaratilgan blokdan tashqarida murojat qilib bo'lmaydi. var esa function-scoped bo‘lib, {} blok scope dan tashqaridagi function ning lexical environmentida yaratiladi va function ichida murojat qilish mumkin.

3. Closure nima?

Closure – bu funksiya o‘zining tashqi lexical environmentiga murojaat qilishi mumkin bo‘lgan holatdir, hatto bu tashqi funksiyaga ishlab tugagan bo‘lsa ham.

Oddiy qilib aytganda: “Ichki funksiya tashqi funksiyadagi o‘zgaruvchilarni eslab qoladi.”

Misol 3: Oddiy closure

function outer() {
  let count = 0;
  return function inner() {
    count++;
    console.log("Count:", count);
  };
}

const counter = outer();
counter(); // Count: 1
counter(); // Count: 2
inner funksiyasi outer tugagan bo‘lsa ham, count o‘zgaruvchisini eslab qolgan.

Misol 4: Closure bilan private o‘zgaruvchilar yaratish

function createUser(name) {
  let secret = "My password is 123";

  return {
    getName: () => name,
    revealSecret: () => secret
  };
}

const user = createUser("Aziz");
console.log(user.getName());       // Aziz
console.log(user.revealSecret()); // My password is 123
Bu usul orqali JavaScript’da encapsulation (yashirish) amalga oshiriladi va bu orqali private variable lar yaratish mumkin.

Misol 5: Loop va Closure muammosi va yechimi (Interview larda ko'p so'raladigan savollardan biri)

// noto‘g‘ri
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log("Wrong:", i), 100);
}
natija: 3,3,3

// Yechimi: `let` dan foydalanish
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log("Correct:", i), 100);
}
natija: 1,2,3
varfunction-scoped (yoki global agar funksiya ichida bo‘lmasa), shuning uchun butun for sikli davomida bitta i o‘zgaruvchisi mavjud bo‘ladi.
setTimeout orqali kechiktirilgan funksiya esa, loop tugagach (i = 3 bo‘lganida) ishga tushadi va har uchalasida ham i = 3 bo‘ladi., let esa har bir iteratsiyada yangi lexical environment yaratadi.


Edge case'lar :

  • Closure orqali katta ma'lumotni eslab qolish (masalan, DOM) – bu browserda memory leak ga olib kelishi mumkin.
  • Keraksiz o‘zgaruvchilarni closure ichida eslab qolish – bu xavfli yoki chalkash holatga olib keladi.
  • Ichma-ich closure’lar chuqur bo‘lsa, debugging va profiling juda qiyinlashadi.

Qachon ishlatish kerak (Use Cases):

  • Closure yordamida ma'lumotni tashqi koddan yashirish mumkin (module pattern)
  • Event handler yoki async kodlarda closure orqali state ni saqlab qolish.
  • Bir nechta sozlamali funksiyalarni yaratishda (partial application, currying).