IlmHamroh
JavaScript Full-stack/8-qism. JavaScript asoslari46/61-dars14 daqiqa
Mundarija (30)

JavaScript IIFE: darhol chaqiriladigan funksiya va funksiya obyekt sifatida

Qisqacha: IIFE (Immediately Invoked Function Expression) — yozilgan zahoti bir marta ishlaydigan funksiya: (function () { ... })();. U ichidagi o'zgaruvchilarni tashqi koddan yashiradi. Bundan tashqari JavaScript'da funksiya — maxsus obyekt: uning name va length xususiyatlari bor, unga o'zingiz ham xususiyat qo'sha olasiz.

Bu darsda

  • IIFE yoza olasiz va nega u qavs ichiga olinishini tushuntira olasiz.
  • IIFE yordamida o'zgaruvchilarni umumiy (global) scope'dan yashira olasiz.
  • Nomli funksiya ifodasini (named function expression) yozasiz va uning nomi qayerda ko'rinishini bilasiz.
  • fn.name va fn.length nima qaytarishini oldindan ayta olasiz.
  • Funksiyaga o'z xususiyatingizni qo'shib, masalan, chaqiruvlar sonini sanay olasiz.

Oldin bilishingiz kerak: Function expression va arrow funksiyalar, Scope asoslari, Funksiya — qiymat: callback va HOF, Rekursiya asoslari.

1. Nega bu kerak?

O'tgan darsda funksiya o'zini o'zi chaqirdi. Bugun funksiyaga boshqa tomondan qaraymiz. Avval bitta amaliy muammo.

Jasur va Malika bitta do'kon sayti ustida ishlayapti. Har biri o'z skriptini yozdi va ikkalasi ham bitta sahifaga ulandi:

html
<script>
  let narx = 25000;
  console.log("Jasurning skripti:", narx);
</script>
<script>
  let narx = 40000;
  console.log("Malikaning skripti:", narx);
</script>

Sahifani ochsangiz, konsolda qizil xato chiqadi:

text
Uncaught SyntaxError: Identifier 'narx' has already been declared

Brauzerda oddiy <script> teglarining eng tashqi o'zgaruvchilari bitta umumiy joyda — global scopeda yashaydi. Ikki dasturchi bir-birining nomini bilmaydi, lekin nomlar to'qnashdi. Katta saytda o'nlab skript bo'ladi — bunday to'qnashuv muqarrar.

Yechim — har kim o'z kodini funksiya ichiga "o'rashi". Scope darsida ko'rganimizdek, funksiya ichidagi o'zgaruvchi tashqariga ko'rinmaydi. Faqat bu funksiya yozilgan zahoti bir marta ishlashi kerak. Aynan shunday funksiya — IIFE.

2. IIFE nima?

2.1 Function expression'dan IIFE'gacha

Function expression darsida funksiyani o'zgaruvchiga saqlashni o'rgandik:

js
const salom = function () {
  console.log("Assalomu alaykum!");
};

salom(); // Assalomu alaykum!

Bu yerda salom — funksiyani ushlab turgan nom, () esa uni chaqiradi. Savol: funksiya faqat bir marta kerak bo'lsa, nomga saqlash shartmi? Yo'q. Funksiya ifodasini qavsga olib, darhol chaqirish mumkin:

js
(function () {
  console.log("Assalomu alaykum!");
})();

Konsolda:

text
Assalomu alaykum!

IIFE (Immediately Invoked Function Expression) — "darhol chaqiriladigan funksiya ifodasi". U yozilgan joyning o'zida bir marta ishlaydi va boshqa hech qachon chaqirilmaydi.

Keling, qismlarini ajratamiz:

Qism Vazifasi
(function () { ... }) Funksiya ifodasi, qavs ichida
() Uni darhol chaqiradi
; Ko'rsatma tugadi

2.2 Nega qavs kerak?

Qavssiz yozib ko'raylik:

js
function () {
  console.log("Assalomu alaykum!");
}();
text
SyntaxError: Function statements require a function name

Tarjimasi: "Funksiya e'loniga nom kerak". JavaScript satr boshida function so'zini ko'rsa, uni e'lon (declaration) deb tushunadi. E'longa esa nom shart va uni shu zahoti chaqirib bo'lmaydi.

Tashqi qavs JavaScript'ga boshqacha xabar beradi: "bu e'lon emas, ifoda — qiymat". Qiymat bo'lgan funksiyani esa darhol chaqirsa bo'ladi.

2.3 Arrow funksiya bilan

Arrow funksiyadan ham IIFE yasash mumkin. Zamonaviy kodda ko'pincha shunday yoziladi:

js
(() => {
  console.log("Arrow IIFE ishladi");
})();

Konsolda:

text
Arrow IIFE ishladi

2.4 IIFE'ga argument berish

IIFE — oddiy funksiya, shuning uchun parametr ham oladi. Argument oxirgi qavs ichiga yoziladi:

js
(function (ism, shahar) {
  console.log(`Xush kelibsiz, ${ism}! Shahar: ${shahar}`);
})("Malika", "Samarqand");

Konsolda:

text
Xush kelibsiz, Malika! Shahar: Samarqand

Tekshirib ko'ring: Quyidagi kod konsolga nima chiqaradi va necha marta?

js
(function (son) {
  console.log(son * 2);
})(21);
Javob

42 — bir marta. Funksiya 21 argumenti bilan darhol chaqirildi va 21 * 2 ni chiqardi. Uni qayta chaqirib bo'lmaydi: funksiyaning nomi ham, uni saqlagan o'zgaruvchi ham yo'q.

3. IIFE va scope: o'zgaruvchilarni yashirish

3.1 Ichkaridagi ichkarida qoladi

IIFE ichida e'lon qilingan o'zgaruvchi tashqariga chiqmaydi:

js
(function () {
  const chegirma = 15;
  console.log(`Bugun chegirma: ${chegirma}%`);
})();

console.log(typeof chegirma);

Konsolda:

text
Bugun chegirma: 15%
undefined

Tashqarida chegirma degan nom umuman yo'q. typeof darsida ko'rganimizdek, noma'lum nom uchun typeof xato bermay "undefined" qaytaradi.

Endi Jasur va Malikaning muammosini hal qilamiz. Har biri o'z kodini IIFE'ga o'raydi:

html
<script>
  (function () {
    let narx = 25000;
    console.log("Jasurning skripti:", narx);
  })();
</script>
<script>
  (function () {
    let narx = 40000;
    console.log("Malikaning skripti:", narx);
  })();
</script>

Endi ikkala narx har biri o'z funksiyasining ichida yashaydi. Ular bir-birini ko'rmaydi va xato yo'q.

3.2 Qoralama daftar: IIFE qiymat qaytaradi

Imtihonda murakkab misolni qoralamada hisoblaysiz. Javobni toza varaqqa ko'chirasiz, qoralamani esa tashlaysiz. IIFE ham shunday ishlay oladi: ichida vaqtinchalik o'zgaruvchilar, tashqariga faqat natija chiqadi.

js
const yetkazishNarxi = (function () {
  const asosiy = 10000; // vaqtinchalik
  const masofa = 7; // km, vaqtinchalik
  const kmNarxi = 2000; // vaqtinchalik
  return asosiy + masofa * kmNarxi;
})();

console.log(yetkazishNarxi); // 24000

yetkazishNarxi ga funksiya emas, uning natijasi yozildi — 24000. asosiy, masofa, kmNarxi esa IIFE tugagach "tashlab yuborildi". Bu usul const ni bir necha qadamli hisob bilan to'ldirish kerak bo'lganda qulay.

3.3 IIFE bugun qanchalik kerak?

IIFE 2015-yilgacha (ES6'dan oldin) juda keng ishlatilgan. O'shanda let, const va modullar yo'q edi — o'zgaruvchini yashirishning yagona yo'li funksiya edi.

Bugun bu vazifani ko'pincha boshqa vositalar bajaradi:

  • Blok { } — let va const blok ichida qoladi, funksiya shart emas.
  • Modullar — <script type="module"> yoki alohida JS fayl o'z scope'iga ega. Ularni modullar darsida o'rganamiz.

Lekin IIFE'ni hali ko'p uchratasiz: eski kodda, sayt statistikasi skriptlarida, bundler (kodni bitta faylga yig'uvchi vosita) chiqargan fayllarda. Asinxron kodda (async () => { ... })() shakli ham bor — uni async/await darsida ko'ramiz.

Tekshirib ko'ring: const natija = (() => 5 * 5)(); qatoridan keyin natija nimaga teng: funksiyagami yoki songami?

Javob

Songa — 25. Oxiridagi () funksiyani darhol chaqirdi, natija ga esa chaqiruv qaytargan qiymat yozildi. Agar oxirgi () bo'lmaganida, natija funksiyaning o'zi bo'lardi.

4. Funksiya — bu ham obyekt

4.1 Funksiyada ham "nuqta" bor

Satrlar bilan ishlaganda .length ni ko'p ishlatdingiz:

js
console.log("Toshkent".length); // 8

Nuqtadan keyingi length — satrning xususiyati (property). Xususiyat — qiymatga biriktirilgan nomli ma'lumot. Masalan, pasport — odamning "obyekti", undagi ism va tug'ilgan yil esa uning xususiyatlari.

Endi kutilmagan narsa: funksiyaning ham xususiyatlari bor!

js
function buyurtmaBer(taom, soni) {
  console.log(`${soni} ta ${taom} buyurtma qilindi`);
}

console.log(buyurtmaBer.name); // buyurtmaBer
console.log(buyurtmaBer.length); // 2
console.log(typeof buyurtmaBer); // function

Ma'lumot turlari darsida JavaScript'da primitiv turlar va obyekt borligini ko'rgan edik. Funksiya obyektlar oilasiga kiradi — u "chaqirsa bo'ladigan maxsus obyekt". typeof unga alohida "function" javobini beradi, lekin ichida u obyekt. Obyektlarni obyektlar darsida to'liq o'rganamiz. Hozir funksiyaning ikki muhim xususiyatini ko'ramiz.

4.2 fn.name — funksiya nomi

name — funksiyaning nomi, satr ko'rinishida. JavaScript uni turli yozuvlarda turlicha aniqlaydi:

js
function salom() {}
const xayr = function () {};
const rahmat = () => {};
const tolov = function click() {};

console.log(salom.name); // salom
console.log(xayr.name); // xayr
console.log(rahmat.name); // rahmat
console.log(tolov.name); // click
Yozuv name Qayerdan olindi
function salom() {} "salom" E'londagi nom
const xayr = function () {} "xayr" O'zgaruvchi nomidan
const rahmat = () => {} "rahmat" O'zgaruvchi nomidan
const tolov = function click() {} "click" Funksiyaning o'z nomi ustun

Nomsiz funksiya to'g'ridan-to'g'ri ishlatilsa, name bo'sh satr bo'ladi. Masalan, callback sifatida berilganda:

js
function nominiAyt(fn) {
  console.log(`Nomi: "${fn.name}"`);
}

nominiAyt(function hisobla() {});
nominiAyt(() => {});

Konsolda:

text
Nomi: "hisobla"
Nomi: ""

Nega nom muhim? Xato chiqqanda JavaScript qaysi funksiyada ekanini aynan shu nom bilan ko'rsatadi. Nomsiz funksiya xato xabarida va DevTools'da (anonymous) — "nomsiz" deb ko'rinadi. Nomsiz funksiyalar ko'p bo'lsa, xatoni qidirish qiyinlashadi.

4.3 fn.length — nechta parametr kutadi

length — funksiya e'lonida nechta parametr yozilganini ko'rsatadi. Nechta argument berilgani emas, nechta kutilgani:

js
function yetkazish(manzil, vaqt) {}
function salomlash() {}
function tolov(summa, valyuta = "so'm", izoh) {}

console.log(yetkazish.length); // 2
console.log(salomlash.length); // 0
console.log(tolov.length); // 1

Oxirgi natijaga e'tibor bering: tolov da uchta parametr, lekin length — 1. Qoida: default qiymatli parametr va undan keyingilar sanalmaydi. length faqat birinchi default'gacha bo'lgan "majburiy" parametrlarni sanaydi.

Kundalik kodda length kam ishlatiladi. U ko'proq kutubxonalar ichida kerak bo'ladi. Masalan, Express (Node.js server kutubxonasi) to'rt parametrli funksiyani oddiy funksiyadan farqlab, uni xatolarni ushlovchi deb taniydi.

Tekshirib ko'ring: const f = (a, b = 1, c) => {}; uchun f.name va f.length nimaga teng?

Javob

f.name — "f": arrow funksiya nomni o'zgaruvchidan oldi. f.length — 1: b default qiymatli, shuning uchun sanash shu yerda to'xtaydi. c ning default'i yo'q, lekin u b dan keyin kelgani uchun sanalmaydi.

4.4 Funksiyaga o'z xususiyatingizni qo'shish

Funksiya obyekt bo'lgani uchun unga o'zingiz ham xususiyat qo'sha olasiz. Masalan, funksiya necha marta chaqirilganini sanaymiz:

js
function taksiChaqir(manzil) {
  taksiChaqir.soni++;
  console.log(`${taksiChaqir.soni}-buyurtma: ${manzil}`);
}

taksiChaqir.soni = 0; // yangi xususiyat

taksiChaqir("Chorsu");
taksiChaqir("Amir Temur xiyoboni");
console.log(`Jami: ${taksiChaqir.soni} ta`);

Konsolda:

text
1-buyurtma: Chorsu
2-buyurtma: Amir Temur xiyoboni
Jami: 2 ta

taksiChaqir.soni = 0 qatori funksiyaga soni degan yangi xususiyat qo'shdi. Hisoblagich alohida global o'zgaruvchida emas, funksiyaning o'zida saqlanyapti. Endi u funksiyadan ajralib qolmaydi.

Funksiyani console.log bilan chiqarsangiz, qo'shgan xususiyatingiz ham ko'rinadi:

js
function taksiChaqir(manzil) {}
taksiChaqir.soni = 2;

console.log(taksiChaqir); // [Function: taksiChaqir] { soni: 2 }

{ soni: 2 } — funksiyaga biriktirilgan xususiyat. Jingalak qavsli bu yozuvni obyektlar darsida batafsil ko'ramiz. Brauzer konsolida ko'rinish biroz boshqacha bo'lishi mumkin — funksiya matni chiqadi, xususiyatlarni esa console.dir(taksiChaqir) bilan ochib ko'rasiz.

Maslahat: Funksiyaga xususiyat qo'shish — kam uchraydigan usul. Hisoblagich va shunga o'xshash "xotira"ni zamonaviy kodda ko'pincha closure bilan yozishadi. Uni closure darsida o'rganamiz. Bu yerdagi asosiy g'oya boshqa: funksiya ham qiymat, ham obyekt.

5. Nomli funksiya ifodasi (named function expression)

5.1 Nom faqat ichkarida ko'rinadi

Yuqorida const tolov = function click() {} ni ko'rdik. Bu — nomli funksiya ifodasi (named function expression): o'z nomi bor funksiya ifodasi. Uning nomi faqat funksiyaning ichida ko'rinadi:

js
const faktorial = function hisobla(n) {
  if (n <= 1) {
    return 1;
  }
  return n * hisobla(n - 1); // ichkarida hisobla ko'rinadi
};

console.log(faktorial(5)); // 120

Tashqaridan esa hisobla degan nom yo'q:

js
const faktorial = function hisobla(n) {
  return n <= 1 ? 1 : n * hisobla(n - 1);
};

hisobla(5);
text
ReferenceError: hisobla is not defined

5.2 Nega bu foydali?

Birinchi foyda — ishonchli rekursiya. Funksiya o'zini tashqi o'zgaruvchi orqali chaqirsa, o'sha o'zgaruvchi o'zgarganda rekursiya buziladi:

js
let fakt = function (n) {
  return n <= 1 ? 1 : n * fakt(n - 1);
};

const nusxa = fakt;
fakt = null; // tashqi nom o'zgardi

nusxa(5);
text
TypeError: fakt is not a function

nusxa(5) ichkarida fakt(4) ni chaqirmoqchi bo'ldi, lekin fakt endi null. Nomli ifodada funksiya o'zini ichki nomi bilan chaqiradi. Tashqarida nima bo'lishidan qat'i nazar, bu nom doim o'sha funksiyani ko'rsatadi.

Ikkinchi foyda — o'qiladigan xato xabarlari. Nomli IIFE, masalan (function sozlamalarniYukla() { ... })();, DevTools'da (anonymous) emas, o'z nomi bilan ko'rinadi.

Tekshirib ko'ring: const a = function b() {}; qatoridan keyin a.name nimaga teng? Tashqarida b() deb chaqirsa bo'ladimi?

Javob

a.name — "b", chunki funksiyaning o'z nomi o'zgaruvchi nomidan ustun. b() ni tashqarida chaqirib bo'lmaydi — ReferenceError: b is not defined chiqadi. b nomi faqat funksiya tanasi ichida mavjud.

6. Ko'p uchraydigan xatolar

6.1 IIFE'ni qavssiz yozish

function () { ... }(); → SyntaxError: Function statements require a function name. Nomli e'londa esa boshqa xabar chiqadi:

js
function salom() {
  console.log("Salom!");
}();
text
SyntaxError: Unexpected token ')'

Ikkala holatda ham sabab bitta: satr boshidagi function e'lon deb o'qildi. Tuzatish: funksiyani qavsga oling — (function () { ... })();.

6.2 Oldingi qatorda nuqta-vergul yo'q

Bu xato tajribali dasturchilarni ham chalg'itadi:

js
const ism = "Ali"
(function () {
  console.log("IIFE ishladi");
})();
text
TypeError: "Ali" is not a function

Birinchi qator oxirida ; yo'q. JavaScript ikki qatorni bitta deb o'qidi: "Ali"(function () {...}). Ya'ni "Ali" satrini funksiya kabi chaqirmoqchi bo'ldi. Tuzatish: oldingi qatorga ; qo'ying. Shu sababli eski kodda ba'zan ;(function () { ... })(); — boshida nuqta-vergulli yozuvni ko'rasiz.

6.3 name ni o'zgartirishga urinish

js
function salom() {}
salom.name = "xayr";

Konsolda xato: TypeError: Cannot assign to read only property 'name' of function 'function salom() {}' — "faqat o'qish uchun bo'lgan name xususiyatiga qiymat yozib bo'lmaydi".

name va length — faqat o'qish uchun (read only). Modul fayllarida bu xato beradi, oddiy <script> da esa o'zgartirish jimgina e'tiborsiz qoldiriladi. Ikkala holatda ham nom o'zgarmaydi. O'zingiz qo'shadigan xususiyatlarga boshqa nom tanlang.

6.4 length argumentlar sonini beradi deb o'ylash

fn.length — e'londagi parametrlar soni. Chaqiruvda nechta argument berilganiga u qaramaydi. Default qiymatli parametr va undan keyingilarni esa umuman sanamaydi.

7. Mashqlar

1-mashq (oson): Salomlashuvchi IIFE

Ikki IIFE yozing:

  1. Oddiy IIFE — konsolga IlmHamroh ishga tushdi deb chiqarsin.
  2. Arrow IIFE — ism parametrini olsin va Xush kelibsiz, Aziz! deb chiqarsin. Argumentni "Aziz" qilib bering.
Yechim
js
(function () {
  console.log("IlmHamroh ishga tushdi");
})();

((ism) => {
  console.log(`Xush kelibsiz, ${ism}!`);
})("Aziz");

Konsolda:

text
IlmHamroh ishga tushdi
Xush kelibsiz, Aziz!

Ikkinchi IIFE'da argument oxirgi qavs ichida: ("Aziz"). Birinchi IIFE oxiridagi ; muhim — busiz ikkinchi IIFE'ning qavsi birinchisining natijasini chaqirishga urinardi.

2-mashq (o'rta): Nom va parametrlar

Quyidagi uch funksiyani yozing. Har biri uchun name va length ni bitta qatorda chiqaring. Avval javobni o'zingiz taxmin qiling, keyin tekshiring.

js
function buyurtma(taom, soni = 1) {}
const yetkazish = (manzil, vaqt) => {};
const tolov = function payme(summa) {};
Yechim
js
function buyurtma(taom, soni = 1) {}
const yetkazish = (manzil, vaqt) => {};
const tolov = function payme(summa) {};

console.log(buyurtma.name, buyurtma.length);
console.log(yetkazish.name, yetkazish.length);
console.log(tolov.name, tolov.length);

Konsolda:

text
buyurtma 1
yetkazish 2
payme 1

buyurtma da soni default qiymatli — shuning uchun length 1. tolov ning nomi payme, chunki funksiyaning o'z nomi o'zgaruvchi nomidan ustun turadi.

3-mashq (qiyin): Taksi hisoblagichi

taksi(masofa) funksiyasini yozing:

  • Safar narxi: 5000 + masofa * 2000 so'm.
  • Har chaqiruvda funksiyaning safarlar xususiyati 1 ga, tushum xususiyati esa safar narxiga oshsin.
  • Har safar konsolga Safar: 3 km — 11000 so'm ko'rinishida yozsin.

Keyin 3, 8 va 1 km lik safarlarni chaqiring. Oxirida Jami: 3 safar, 39000 so'm chiqsin.

Yechim
js
function taksi(masofa) {
  const narx = 5000 + masofa * 2000;
  taksi.safarlar++;
  taksi.tushum += narx;
  console.log(`Safar: ${masofa} km — ${narx} so'm`);
}

taksi.safarlar = 0;
taksi.tushum = 0;

taksi(3);
taksi(8);
taksi(1);
console.log(`Jami: ${taksi.safarlar} safar, ${taksi.tushum} so'm`);

Konsolda:

text
Safar: 3 km — 11000 so'm
Safar: 8 km — 21000 so'm
Safar: 1 km — 7000 so'm
Jami: 3 safar, 39000 so'm

Xususiyatlar funksiya birinchi marta chaqirilishidan oldin 0 ga tenglashtirilishi shart. Aks holda taksi.safarlar++ undefined ga 1 qo'shib, NaN hosil qiladi.

8. Real ishda

  • Sayt statistikasi: Yandex Metrika yoki Google Tag Manager saytga qo'shish uchun beradigan kod IIFE ichiga o'ralgan. Shunda ularning o'zgaruvchilari sizning kodingizga aralashmaydi.
  • Bundler'lar: esbuild, Rollup kabi vositalar kodni brauzer uchun yig'ganda IIFE formatida chiqarishi mumkin (format: "iife").
  • Eski kod: jQuery plaginlari va 2015-yilgacha yozilgan loyihalar IIFE'ga to'la. Ularni o'qiy olish ish joyida kerak bo'ladi.
  • Xatolarni qidirish: fn.name xato xabarlarida va loglarda ko'rinadi. Funksiyalarga aniq nom bering — keyinroq o'zingizga oson bo'ladi.
  • Intervyu: "IIFE nima va nega ishlatilgan?", "Funksiya JavaScript'da obyektmi?" — boshlang'ich darajadagi klassik savollar.

Xulosa

  • IIFE — (function () { ... })(); — yozilgan zahoti bir marta ishlaydigan funksiya.
  • Tashqi qavs function so'zini e'lon emas, ifoda qiladi — shuning uchun uni darhol chaqirsa bo'ladi.
  • IIFE ichidagi o'zgaruvchilar tashqariga chiqmaydi; bugun bu ishni ko'pincha blok va modullar bajaradi.
  • Funksiya — maxsus obyekt: name (nomi) va length (default'gacha parametrlar soni) xususiyatlari bor.
  • Funksiyaga o'z xususiyatingizni qo'sha olasiz: taksi.safarlar = 0.
  • Nomli funksiya ifodasining nomi faqat ichkarida ko'rinadi va rekursiyani ishonchli qiladi.

Keyingi dars: DevTools bilan debug qilish — kodni to'xtatib, qadamma-qadam bajarib, xatoni aniq topishni o'rganamiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript IIFE: darhol chaqiriladigan funksiya va funksiya obyekt sifatida — IlmHamroh