Series: JavaScript Basics Lesson 15

Lexical Scope

Lexical Scope nima, Execution Context qanday ishlaydi, Creation va Execution Phase, Scope turlari va Scope Chain — barchasi bitta darsda.

15-dars

Lexical Scope

Scope nima o'zi?

Scope — o'zgaruvchi qayerdan ko'rinadi, qayerdan ko'rinmaydi — shu chegara.

Tarixan ikkita scope turi mavjud bo'lgan:

Tur Ma'nosi Qayerda
Lexical (Static) Kod yozilgan joyga qarab JS, Python, C
Dynamic Funksiya chaqirilgan joyga qarab Bash, Perl (eski)

JS lexical scope ishlatadi. Bu shuni anglatadiki — o'zgaruvchining qaysi scopeda ekanligi siz kod yozayotgan paytda aniqlanadi, program ishlaganda emas.


Oddiy misol — farqni ko'rish uchun

const x = 'global';

function foo() {
  console.log(x); // qaysi x?
}

function bar() {
  const x = 'local';
  foo();
}

bar(); // 'global'

Ko'pchilik 'local' deb o'ylaydi. Lekin natija — 'global'.

Sababi: foo bar ichidan chaqirildi, lekin foo yozilgan joy — global scope. Lexical scope yozilgan joyga qaraydi, chaqirilgan joyga emas.

Dynamic scope bo'lganda 'local' chiqardi. JS bunday emas.


Execution Context da

Haqiqatda JS engine (V8) kodni ishga tushirganda Execution Context degan obyekt yaratadi. Va bu context ikki fazada quriladi.

Execution Context ning ichki tuzilishi

Har bir Execution Context 3 narsadan iborat:

Execution Context {
  1. Lexical Environment   → o'zgaruvchilar, scope chain
  2. Variable Environment  → var va function deklaratsiyalari
  3. ThisBinding           → this qiymati
}

"Lexical Scope" aslida shu Lexical Environment ning natijasidir.


Ikki faza

1-faza: Creation Phase (Memory Creation Phase)

Funksiya chaqirilgan zahoti, lekin birorta qator kod ishlamasdan oldin, V8:

  • Yangi Execution Context yaratadi
  • Lexical Environment ni tuzadi
  • Scope chain ni [[Environment]] orqali ulaydi (parent ga pointer)
  • var larni undefined bilan, function declaration larni to'liq qiymati bilan hoisting qiladi
  • this ni belgilaydi

2-faza: Execution Phase

Endi V8 kodni qator-qator ishlatadi — qiymatlarni biriktiradi, funksiyalarni chaqiradi.

function greet(name) {
  console.log(message); // undefined (hoisted, qiymat yo'q)
  var message = 'Salom, ' + name;
  console.log(message); // 'Salom, Ali'
}

greet('Ali');

Creation Phase da (greet chaqirilgan zahoti, birinchi console.log dan oldin):

Execution Context {
  LexicalEnvironment: {
    name: 'Ali',        // argument — darhol qiymat bilan
    message: undefined  // var — hoisted, qiymatsiz
  }
}

Scope turlari JS da

// 1. Global Scope
const a = 1;

function outer() {
  // 2. Function Scope
  const b = 2;

  if (true) {
    // 3. Block Scope (ES6 dan beri, faqat let/const)
    const c = 3;
    var d = 4; // var block scope GA KIRMAYDI!
  }

  console.log(b); // 2 ✅
  console.log(d); // 4 ✅  — var function scope da
  console.log(c); // ReferenceError ❌ — c bu yerda yo'q
}
  • var — function scope (ES6 dan oldin yagona usul edi)
  • let, const — block scope {}

Scope Chain — zanjir qanday ishlaydi

const planet = 'Earth';

function continent() {
  const country = 'Uzbekistan';

  function city() {
    const name = 'Tashkent';
    console.log(name);    // o'zida bor
    console.log(country); // bir yuqorida
    console.log(planet);  // ikki yuqorida
  }

  city();
}

continent();

V8 city ichida o'zgaruvchi qidirganda:

city scope       → name bor ✅, country yo'q, planet yo'q
  ↑
continent scope  → country bor ✅, planet yo'q
  ↑
global scope     → planet bor ✅
  ↑
null             → zanjir tugadi → ReferenceError

Bu zanjir parse vaqtida quriladi va o'zgarmaydi.