IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur28/65-dars21 daqiqa
Mundarija (33)

JavaScript this: to'rt qoida va arrow funksiya istisnosi

Qisqacha: this — funksiya ichidagi maxsus so'z. Uning qiymati funksiya qayerda yozilganiga emas, qanday chaqirilganiga bog'liq. To'rt qoida bor: obyekt.metod() — this o'sha obyekt; oddiy f() — strict rejimda undefined; f.call(x) — this = x; new F() — this = yangi obyekt. Arrow funksiya istisno: uning o'z this i yo'q, u this ni o'zi yozilgan joydan oladi.

Bu darsda

  • Har qanday chaqiruvga qarab this nimaga teng bo'lishini to'rt qoida bilan aniqlay olasiz.
  • Qoidalar to'qnashganda qaysi biri ustun kelishini bilasiz.
  • Arrow funksiya nega this ni "tashqaridan" olishini va buni qayerda foydali ishlatishni tushuntira olasiz.
  • Node (.mjs va .cjs) va brauzerdagi (<script> va type="module") farqlarni bilasiz.
  • vazifalar dagi tinglovchilarni tekshirib, "this o'rniga event" qarorini hujjatlashtirasiz.

Oldin bilishingiz kerak: Shorthand, computed kalitlar va metodlar, Function expression va arrow funksiyalar, Global obyekt va globalThis, Strict mode, addEventListener asoslari.

1. Nega bu kerak?

this bilan ikki marta uchrashgansiz. Metodlar darsida hamyon.korsat() ichidagi this — hamyon edi. addEventListener asoslari darsida esa oddiy function tinglovchidagi this — tugma edi, arrow funksiyadagisi — window.

O'shanda ikkala safar ham "to'liq qoidalar keyinroq" degan edik. Sababi bor: this JavaScript'dagi eng ko'p chalkashtiradigan so'zlardan biri. Bir xil this.ism bitta joyda "Ali", boshqa joyda undefined, uchinchi joyda esa TypeError beradi. Kod o'zgarmagan — faqat funksiya boshqacha chaqirilgan.

Hayotdan o'xshatish: "men" so'zi. Otabek "men ofitsiantman" desa, "men" — Otabek. Rustam aka xuddi shu gapni aytsa, "men" — Rustam aka. Gap bir xil, ma'nosi esa kim aytayotganiga bog'liq. this ham shunday: funksiya bitta, this esa uni kim va qanday chaqirganiga qarab o'zgaradi.

Bugun shu "kim chaqirdi?" savoliga javob beradigan to'rtta qoidani o'rganamiz. Keyin ularning yagona istisnosi — arrow funksiyani ko'ramiz. Oxirida Node va brauzer qanday farq qilishini aniq ko'rib chiqamiz.

2. this — chaqiruv paytida aniqlanadi

2.1 Bitta funksiya — ikki xil this

«Bahor» xodimlari o'zini tanishtiradi. Funksiyani bir marta yozamiz va ikkita obyektga metod qilib beramiz:

js
function tanishtir() {
  console.log(`${this.ism} — ${this.lavozim}`);
}

const otabek = { ism: "Otabek", lavozim: "ofitsiant", tanishtir };
const rustam = { ism: "Rustam aka", lavozim: "oshpaz", tanishtir };

otabek.tanishtir();
rustam.tanishtir();

Konsolda:

text
Otabek — ofitsiant
Rustam aka — oshpaz

tanishtir funksiyasi xotirada bitta. otabek.tanishtir va rustam.tanishtir — o'sha bitta funksiyaga ikkita havola (Havola semantikasi). Lekin natija ikki xil chiqdi. Demak this funksiya yozilganda emas, har chaqiruvda qaytadan aniqlanadi.

Qadamma-qadam yuring. Har chaqiruvda this ga nima tushishini kuzating:

2.2 Bitta savol: "qanday chaqirildi?"

this ni aniqlash uchun funksiyaning ichiga qaramang. Uni chaqirgan qatorni toping va to'rt savol bering:

  1. new bilan chaqirildimi?
  2. call (yoki uning qarindoshlari) bilan chaqirildimi?
  3. obyekt.metod() shaklida — nuqta bilan chaqirildimi?
  4. Hech biri emas — oddiy f() mi?

Har savolning o'z qoidasi bor. Ularni eng ko'p uchraydiganidan boshlab ko'ramiz, ustuvorlik tartibini esa oxirida yig'amiz.

3. 1-qoida: metod sifatida chaqiruv

3.1 Nuqtadan oldingi obyekt

Bu qoidani 08-qismdan bilasiz: obyekt.metod() chaqirilsa, this — nuqtadan oldingi obyekt. Inglizcha nomi — implicit binding ("yashirin bog'lanish"): this ni hech kim aniq aytmadi, uni chaqiruv shaklining o'zi bildirdi.

Muhim so'z — chaqirilsa. Funksiya qaysi obyekt ichida yozilgani emas, chaqiruv qatorida nuqtadan oldin nima turgani hal qiladi. «Bitta funksiya — ikki xil this» bo'limida tanishtir hech qaysi obyekt ichida yozilmagan edi, lekin baribir ikkalasida to'g'ri ishladi.

3.2 Kvadrat qavs va ichma-ich obyekt

Nuqta o'rniga kvadrat qavs ham xuddi shunday ishlaydi. Ichma-ich obyektda esa oxirgi nuqtadan oldingi obyekt olinadi:

js
const bahor = {
  nom: "Bahor",
  oshxona: {
    oshpaz: "Rustam aka",
    kim() {
      return this.oshpaz;
    },
  },
};

console.log(bahor.oshxona.kim()); // Rustam aka
console.log(bahor["oshxona"]["kim"]()); // Rustam aka

bahor.oshxona.kim() da ikkita nuqta bor. kim dan oldingi obyekt — bahor.oshxona. Shuning uchun this — oshxona, bahor emas. this.nom yozsangiz undefined chiqardi: oshxona da nom yo'q.

Tekshirib ko'ring: const a = { x: 1, b: { x: 2, f() { return this.x; } } }; bo'lsa, a.b.f() nima qaytaradi?

Javob

2. f dan oldingi obyekt — a.b, demak this.x — a.b.x. Tashqi a dagi x: 1 ga this umuman qaramaydi.

4. 2-qoida: oddiy chaqiruv

4.1 Strict rejimda — undefined

Endi o'sha tanishtir ni nuqtasiz, oddiy funksiya kabi chaqiramiz:

js
"use strict";

function tanishtir() {
  console.log(`${this.ism} — ${this.lavozim}`);
}

tanishtir();
text
TypeError: Cannot read properties of undefined (reading 'ism')

Tarjimasi: "undefined ning xususiyatlarini o'qib bo'lmaydi (ism ni o'qishda)". Nuqtadan oldin hech narsa yo'q — hech kim "men chaqirdim" demadi. Bu default binding ("sukut bo'yicha bog'lanish"): strict rejimda bunday chaqiruvda this — undefined. undefined.ism ni o'qishga urinish esa TypeError beradi.

Birinchi qatordagi "use strict"; ga e'tibor bering. this ni sinayotganda kod qayerda ishlashi muhim. Node'dagi .mjs fayl — modul, modul esa doim strict. Saytdagi «Ishga tushir» tugmasi ham kodni brauzerda strict rejimda bajaradi. Bu va keyingi darslarning ba'zi misollari baribir "use strict"; bilan boshlanadi: kodni .cjs faylga yoki oddiy <script> ga ko'chirsangiz ham, natija o'zgarmasin (Strict mode). Bitta farq qoladi — eng yuqori darajadagi this: Node modulida u undefined, brauzer skriptida esa (strict bo'lsa ham) window. Buni «Eng yuqori darajadagi this» bo'limida ko'ramiz.

4.2 Oddiy skriptda — global obyekt

Strict bo'lmagan ("sloppy", ya'ni "bo'sh") rejimda qoida boshqacha: this o'rniga global obyekt qo'yiladi. Xuddi shu kodni oddiy skript sifatida — .cjs faylda — ishga tushiramiz:

js
function kim() {
  return this;
}

console.log(kim() === globalThis); // true

Endi this — globalThis. Xato chiqmaydi, lekin bu yaxshilik emas. this.ism jimgina undefined beradi, this.ism = "Ali" esa global obyektga yangi xususiyat yozib qo'yadi:

js
function ismQoy(ism) {
  this.ism = ism;
}

ismQoy("Ali");
console.log(globalThis.ism); // Ali

ismQoy hech qaysi obyektga tegishli emas. U "o'z" obyektiga ism yozmoqchi edi, lekin this global obyekt bo'lib chiqdi. Endi butun dasturda ism degan global nom paydo bo'ldi. U boshqa kodning shu nomli o'zgaruvchisi bilan to'qnashishi mumkin (Global obyekt va globalThis). Strict rejim aynan shu jim xatoni baland ovozli TypeError ga aylantiradi — Strict mode darsidagi asosiy g'oya.

4.3 Eng yuqori darajadagi this

Funksiyadan tashqarida — faylning eng yuqori darajasida — ham this bor. U muhitga bog'liq. Bitta qatorni ikki faylda — bosh.mjs va bosh.cjs da — node bilan ishga tushiring:

js
console.log(this);

.mjs modulda — undefined. .cjs faylda esa — {}, bo'sh obyekt. Biz ikkalasini Node 24 da tekshirdik. Bu qatorni saytdagi tugma bilan emas, fayl bilan sinang: brauzer skriptida u Window obyektini chiqaradi.

Bu {} — Node'ning CommonJS tizimi har faylga beradigan module.exports obyekti. CommonJS'ni CommonJS va ESM darsida o'rganamiz — hozir bilish shart emas.

To'rt muhitni yonma-yon yig'amiz. Ikkinchi ustun — eng yuqori darajadagi this, uchinchisi — oddiy f() ichidagi this:

Muhit Yuqori daraja Oddiy f() ichida
Node, .mjs (modul) undefined undefined
Node, .cjs {} globalThis
Brauzer, <script> window window
Brauzer, type="module" undefined undefined

Funksiya ichida qoida bitta: modulda va strict rejimda — undefined, eski uslubdagi skriptda — global obyekt. Yuqori darajada esa: modulda — undefined, skriptda — global obyekt (Node .cjs da — {}). Zamonaviy kod deyarli doim modul, shuning uchun asosan birinchi va to'rtinchi qatorlarni uchratasiz.

Tekshirib ko'ring: .mjs faylda function f() { return this; } va console.log(f()); yozildi. Nima chiqadi? .cjs da-chi?

Javob

.mjs da — undefined: modul strict, oddiy chaqiruvda this yo'q. .cjs da — global obyekt (globalThis), chunki u strict emas. .cjs dagi {} — faqat yuqori darajadagi this; funksiya ichida esa qoida boshqa.

5. 3-qoida: call bilan aniq berish

Ba'zan this ni o'zimiz tanlagimiz keladi. Har funksiyada call degan metod bor: f.call(obyekt) funksiyani darhol chaqiradi va this ga obyekt ni qo'yadi. Bu explicit binding ("aniq bog'lanish"):

js
function tanishtir() {
  return `${this.ism}: ${this.lavozim}`;
}

const jasur = { ism: "Jasur aka", lavozim: "egasi" };

console.log(tanishtir.call(jasur)); // Jasur aka: egasi

jasur da tanishtir metodi yo'q. Lekin call funksiyani "go'yo jasur ning metodidek" chaqirdi. call ning to'liq imkoniyatlari, uning ikki qarindoshi — apply va bind — call, apply, bind darsida. Hozircha bitta narsani eslab qoling: call ga birinchi bo'lib berilgan narsa — this.

6. 4-qoida: new bilan chaqirish

To'rtinchi qoida funksiyani new kalit so'zi bilan chaqirganda ishlaydi:

js
function Buyurtma(taom) {
  this.taom = taom;
  this.holati = "kutilmoqda";
}

const birinchi = new Buyurtma("Osh");
console.log(birinchi);

Konsolda:

text
Buyurtma { taom: 'Osh', holati: 'kutilmoqda' }

Node obyekt oldiga funksiya nomini — Buyurtma ni — yozib qo'ydi: "bu obyektni Buyurtma yasagan".

new avval yangi bo'sh obyekt yaratadi, keyin funksiyani shu obyektni this qilib chaqiradi. Funksiya return yozmasa ham, new o'sha yangi obyektni qaytaradi. Shunday new bilan chaqirish uchun yozilgan funksiya konstruktor (constructor) deyiladi — xuddi qolipdan bir xil g'isht quyadigan usta kabi. Nom katta harf bilan boshlangani — "bu new bilan chaqiriladi" degan kelishuv. Bu mexanizmning to'rt qadami Konstruktor funksiya va new darsida — hozir faqat qoidani eslab qoling: new F() da this — yangi obyekt.

7. Qoidalar to'qnashsa: ustuvorlik

Bitta chaqiruvda ikki qoida bir vaqtda "ishlashi" mumkin. Masalan, nuqta ham bor, call ham:

js
function tanishtir() {
  return this.ism;
}

const otabek = { ism: "Otabek", tanishtir };
const jasur = { ism: "Jasur aka" };

console.log(otabek.tanishtir.call(jasur)); // Jasur aka

Nuqtadan oldin otabek turibdi, lekin call ga jasur berilgan. Natija — Jasur aka: aniq aytilgan this yashirinidan kuchli.

To'liq tartib — kuchlidan kuchsizga:

O'rin Qoida Chaqiruv this
1 new new F() yangi obyekt
2 Aniq f.call(x) x
3 Metod obj.f() obj
4 Oddiy f() undefined yoki global

new hatto aniq bog'lashdan ham kuchli — buni bind bilan keyingi darslarda ko'ramiz. Bu ro'yxatning tepasida yana bitta tekshiruv turadi: funksiya arrow'mi? Arrow bo'lsa, to'rt qoidaning hech biri ishlamaydi. Sxemani yuqoridan pastga o'qing — bu this ni aniqlashning to'liq algoritmi:

flowchart TD
  A{"Arrow funksiyami?"} -- "ha" --> L["Yozilgan joydagi this"]
  A -- "yo'q" --> N{"new F() ?"}
  N -- "ha" --> Y["Yangi obyekt"]
  N -- "yo'q" --> C{"f.call(x) ?"}
  C -- "ha" --> X["x"]
  C -- "yo'q" --> M{"obj.f() ?"}
  M -- "ha" --> O["obj"]
  M -- "yo'q" --> D["Strict: undefined<br/>Skript: global"]

Tekshirib ko'ring: rustam.tanishtir.call(otabek) — this kim?

Javob

otabek. Nuqtadan oldin rustam, lekin call (aniq bog'lanish) metod qoidasidan ustun. Sxemada call savoli obj.f() savolidan oldin keladi.

8. Arrow funksiya istisnosi

8.1 Arrow'da o'z this yo'q

Arrow funksiyalar darsida "arrow'da this boshqacha ishlaydi" degan edik. Endi aniq aytamiz: arrow funksiyaning o'z this i yo'q. Uning ichida this yozsangiz, JavaScript uni oddiy o'zgaruvchidek tashqi scope dan qidiradi — arrow yozilgan joydagi this ni oladi. Buni leksik this deyishadi ("leksik" — "kod matnida qayerda turganiga qarab").

Shuning uchun metodni arrow bilan yozish ishlamaydi:

js
const otabek = {
  ism: "Otabek",
  tanishtir: () => this?.ism,
};

console.log(otabek.tanishtir()); // undefined

Arrow obyekt ichida yozilgandek ko'rinadi. Lekin obyekt literali o'zining this ini yaratmaydi — { } qavslari funksiya emas. Arrow yozilgan joy — faylning eng yuqori darajasi. U yerda this modulda undefined, brauzer skriptida window — ikkalasida ham ism yo'q. Metodlar darsidagi "metodni arrow bilan yozmang" qoidasining sababi shu.

8.2 Metod ichidagi callback — arrow'ning eng yaxshi joyi

Arrow'ning bu xususiyati kamchilik emas — ko'pincha aynan kerakli narsa. «Bahor» menyusini chiqaradigan metodni ko'ring:

js
const menyu = {
  nom: "Bahor",
  taomlar: ["osh", "manti"],
  chiqar() {
    this.taomlar.forEach((taom) => {
      console.log(`${this.nom}: ${taom}`);
    });
  },
};

menyu.chiqar();

Konsolda:

text
Bahor: osh
Bahor: manti

chiqar — oddiy metod, menyu.chiqar() chaqirildi, demak uning this i — menyu. Ichidagi arrow callback'ning o'z this i yo'q, u chiqar niki bilan bir xil. Shuning uchun this.nom — "Bahor".

Endi callback'ni oddiy function ga almashtiring:

js
"use strict";

const menyu = {
  nom: "Bahor",
  taomlar: ["osh"],
  chiqar() {
    this.taomlar.forEach(function () {
      console.log(this);
    });
  },
};

menyu.chiqar(); // undefined

forEach callback'ni oddiy chaqiradi — callback(element, index, array), nuqtasiz. Oddiy function ning o'z this i bor va u 2-qoida bo'yicha undefined bo'ldi. Ichki funksiya tashqi metodning this ini "meros" olmaydi.

Arrow paydo bo'lishidan (2015) oldin dasturchilar bu muammoni const self = this; bilan aylanib o'tishgan: tashqi this ni oddiy o'zgaruvchiga saqlab, callback ichida self.nom deb yozishgan. Eski kodda self yoki that ni ko'rsangiz — sababi shu. Bu self — oddiy o'zgaruvchi nomi; Global obyekt darsidagi brauzerning global self i bilan aloqasi yo'q, uni shunchaki to'sib qo'yadi.

8.3 Arrow'ni qayta bog'lab bo'lmaydi

Arrow'ning this i yozilgan paytda "qotadi". Uni hech narsa o'zgartira olmaydi — call ham, new ham:

js
const kimArrow = () => this?.ism;

console.log(kimArrow.call({ ism: "Ali" })); // undefined

call berilgan obyektni jimgina e'tiborsiz qoldirdi. new esa umuman ishlamaydi:

js
const Buyurtma = (taom) => {
  this.taom = taom;
};

new Buyurtma("Osh");
text
TypeError: Buyurtma is not a constructor

Tarjimasi: "Buyurtma — konstruktor emas". Arrow'ning this i yo'q — new yangi obyektni qo'yadigan joy topa olmaydi. Shuning uchun arrow'ni new bilan chaqirib bo'lmaydi.

Callback imzosi darsida va'da qilingan thisArg ham shu yerda tushunarli bo'ladi. forEach(callback, thisArg) ning ikkinchi argumenti oddiy function callback uchun this bo'ladi, arrow'ga esa ta'sir qilmaydi:

js
const bahor = { nom: "Bahor" };

[1].forEach(function () {
  console.log(this.nom);
}, bahor);

[1].forEach(() => {
  console.log(this?.nom);
}, bahor);

Konsolda:

text
Bahor
undefined

Zamonaviy kodda thisArg deyarli ishlatilmaydi: arrow callback tashqi this ni o'zi ko'radi.

Tekshirib ko'ring: Nega «Metod ichidagi callback» bo'limidagi birinchi chiqar ishladi, ikkinchisi esa yo'q? Bitta gap bilan.

Javob

Arrow callback'ning o'z this i yo'q va u chiqar ning this ini (menyu) oladi; oddiy function callback'ning esa o'z this i bor va forEach uni nuqtasiz chaqirgani uchun u undefined bo'ladi.

9. Brauzerda: hodisa tinglovchisidagi this

addEventListener asoslari darsida oddiy function tinglovchida this — element ekanini ko'rgan edik. Endi buning qaysi qoida ekanini aytamiz: brauzer tinglovchini o'zi chaqiradi va this ga tinglovchi turgan elementni aniq qo'yadi. Ya'ni bu — 3-qoida, aniq bog'lanish. Bu element — event.currentTarget (Event obyekti).

Quyidagi natijada ikki skript bor: oddiy <script> va type="module". Har birida bittadan tugma, har tugmada ikkitadan tinglovchi — oddiy function va arrow:

html
<style>
  body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
  button { font: inherit; padding: 0.4rem 1rem; margin: 0.25rem; }
</style>
<button id="osh" type="button">Osh (skript)</button>
<button id="manti" type="button">Manti (modul)</button>
<script>
  console.log("skript:", this === window);
  const osh = document.getElementById("osh");
  osh.addEventListener("click", function (event) {
    console.log("function:", this === event.currentTarget);
  });
  osh.addEventListener("click", () => {
    console.log("arrow:", this === window);
  });
</script>
<script type="module">
  console.log("modul:", this);
  const manti = document.getElementById("manti");
  manti.addEventListener("click", function () {
    console.log("function:", this.id);
  });
  manti.addEventListener("click", () => {
    console.log("arrow:", this);
  });
</script>

Sahifa ochilishi bilan konsolda:

text
skript: true
modul: undefined

Endi tugmalarni bosing. «Osh (skript)» konsolga function: true va arrow: true yozadi. «Manti (modul)» esa function: manti va arrow: undefined yozadi. Biz buni Chrome'da tekshirdik.

Nimaga qarash kerak:

  • Oddiy function — ikkala skriptda ham element. Modul strict, lekin bu yerda this ni brauzer aniq bergan. Strict rejim faqat "hech kim bermagan" holatda (2-qoida) undefined qo'yadi.
  • Arrow — yozilgan joydagi this. Oddiy skriptning eng yuqori darajasida u window, modulda — undefined. Arrow tinglovchida this.classList yozsangiz, birinchisida window.classList (undefined), ikkinchisida undefined.classList — ikkalasida ham TypeError.
  • Delegation'da this — tinglovchi turgan ota element, bosilgan tugma emas (Event delegation).

Shuning uchun zamonaviy kodda tinglovchida this deyarli yozilmaydi. Element kerak bo'lsa — event.currentTarget, bosilgan narsa kerak bo'lsa — event.target. Ular arrow'da ham, function da ham bir xil ishlaydi va kodni o'qigan odam "bu yerda this nima ekan?" deb o'ylamaydi.

10. Ko'p uchraydigan xatolar

10.1 Metod arrow bilan yozilgan

«Arrow'da o'z this yo'q» bo'limidagi tanishtir: () => this — eng ko'p uchraydigan xato. Modulda this.ism o'qilsa — TypeError: Cannot read properties of undefined (reading 'ism'). Oddiy skriptda xato chiqmaydi, faqat undefined — bu yanada xavfli. Tuzatish: metod shorthand — tanishtir() { ... }.

10.2 Ichki function tashqi this ni kutadi

Metod ichida forEach(function () { this... }) yoki setTimeout(function () { this... }) — ichki funksiyaning this i boshqa. Tuzatish: ichki callback'ni arrow qiling.

10.3 this. ni unutish

js
const hamyon = {
  balans: 50000,
  toldir(summa) {
    balans += summa;
  },
};

hamyon.toldir(1000);
text
ReferenceError: balans is not defined

Tarjimasi: "balans aniqlanmagan". Metod ichida xususiyat nomi o'z-o'zidan o'zgaruvchiga aylanmaydi. JavaScript balans ni scope zanjiri bo'ylab qidirdi va topmadi. Tuzatish: this.balans += summa;.

10.4 this — funksiyaning o'zi deb o'ylash

this funksiyani ham, uning scope'ini ham bildirmaydi. U faqat chaqiruv shakliga qarab tanlangan obyekt (yoki undefined). Funksiyaning o'z o'zgaruvchilari — scope'da, this da emas.

11. Mashqlar

1-mashq (oson): this kim?

Kodni ishga tushirmasdan, har console.log nima chiqarishini yozing. Keyin tekshiring.

js
"use strict";

function nom() {
  return this?.nom;
}

const stol = { nom: "5-stol", nom };
const zal = { nom: "Katta zal", stol };

console.log(stol.nom());
console.log(zal.stol.nom());
console.log(nom());
console.log(nom.call(zal));

Ishora: ?. — optional chaining: this undefined bo'lsa, xato o'rniga undefined qaytadi. { nom: "5-stol", nom } da kalit ikki marta yozilgan — ikkinchisi birinchisining ustidan yozadi.

Yechim

Shoshilmang — bu mashqda tuzoq bor. { nom: "5-stol", nom } da ikkinchi nom (funksiya) birinchisining (satrning) ustidan yozildi. Demak stol.nom — funksiya, this.nom ham o'sha funksiya:

js
"use strict";

function nom() {
  return this?.nom;
}

const stol = { nom: "5-stol", nom };
const zal = { nom: "Katta zal", stol };

console.log(stol.nom());
console.log(zal.stol.nom());
console.log(nom());
console.log(nom.call(zal));

Konsolda:

text
[Function: nom]
[Function: nom]
undefined
Katta zal

Birinchi ikkitasida this — stol (ikkinchisida ham oxirgi nuqtadan oldin stol), stol.nom esa funksiya. Uchinchisi — oddiy chaqiruv, this — undefined, ?. xatoni to'xtatdi. To'rtinchisida call this ga zal ni qo'ydi. Saboq: xususiyat va metodga bir xil nom bermang.

2-mashq (o'rta): Kassani tuzating

Kassa metodlari ishlamayapti. Ikki xatoni toping va tuzating — natija Jami: 63000 so'm bo'lsin.

js
const kassa = {
  cheklar: [35000, 28000],
  jami: 0,
  hisobla: () => {
    this.cheklar.forEach(function (summa) {
      this.jami += summa;
    });
  },
};

kassa.hisobla();
console.log(`Jami: ${kassa.jami} so'm`);
Yechim
js
const kassa = {
  cheklar: [35000, 28000],
  jami: 0,
  hisobla() {
    this.cheklar.forEach((summa) => {
      this.jami += summa;
    });
  },
};

kassa.hisobla();
console.log(`Jami: ${kassa.jami} so'm`); // Jami: 63000 so'm

Birinchi xato — metod arrow edi: uning this i modulda undefined. Metod shorthand bilan kassa.hisobla() da this — kassa. Ikkinchi xato — ichki callback oddiy function edi: forEach uni nuqtasiz chaqiradi va this — undefined. Arrow callback esa hisobla ning this ini oladi. Qoida: tashqi — metod, ichki — arrow.

3-mashq (qiyin): Ikki muhit

Quyidagi kod .mjs da va .cjs da ishga tushirilsa, har qator nima chiqaradi? Jadval tuzing, keyin ikkala faylni node bilan ishga tushirib tekshiring (saytdagi tugma bu yerda yordam bermaydi — u brauzer skripti).

js
function f() {
  return this === globalThis;
}
const g = () => this;

console.log(f());
console.log(g());
console.log(typeof this);
Yechim

.mjs da:

js
function f() {
  return this === globalThis;
}
const g = () => this;

console.log(f());
console.log(g());
console.log(typeof this);

Konsolda:

text
false
undefined
undefined

.cjs da:

js
function f() {
  return this === globalThis;
}
const g = () => this;

console.log(f());
console.log(g());
console.log(typeof this);

Konsolda:

text
true
{}
object
Qator .mjs .cjs
f() false — strict, this = undefined true — sloppy, global
g() undefined {} — module.exports
typeof this "undefined" "object"

g — arrow, shuning uchun u faylning yuqori darajasidagi this ni qaytaradi. .cjs da u {} (module.exports), global obyekt emas! Oddiy f ichida esa .cjs da global obyekt. Bitta faylda uch xil this — shuning uchun zamonaviy kod modullarda yoziladi.

4-mashq: Vazifalar qadami — this auditi

Bu va keyingi ikki darsda vazifalar ning xulqini o'zgartirmaymiz. Avval tekshiruv: vazifalar.js da this bormi va bo'lishi kerakmi?

1. Branch. git switch -c refactor/this-va-bind — u keyingi ikki darsda ham davom etadi.

2. Jadval. vazifalar.js da oltita tinglovchi bor. Har biri uchun yozing: funksiya turi, element qayerdan olinadi va ichida this yozilsa, u nima bo'lardi. Ishora: vazifalar.js <script defer> bilan ulangan — u oddiy skript, modul emas (Yakuniy loyiha).

3. Tajriba. Saytni Live Server'da oching, DevTools Console'ga quyidagini yozing va «Faol» ni bosing:

js
filtrlar.addEventListener("click", function (event) {
  console.log(this === event.currentTarget);
  console.log(`${this.id} / ${event.target.dataset.filtr}`);
});

filtrlar — vazifalar.js ning yuqori darajasidagi const. Oddiy skriptdagi bunday o'zgaruvchilar konsoldan ham ko'rinadi. Sahifani yangilasangiz, bu vaqtinchalik tinglovchi yo'qoladi.

4. Qaror. Natijaga qarab README.md ga "Kod qoidalari" bo'limini qo'shing: tinglovchilarda this ishlatamizmi yoki yo'qmi va nega.

Yechim

Jadval:

Tinglovchi Turi Element qayerdan this bo'lardi
forma — submit arrow maydon, forma window
maydon — input arrow maydon window
royxat — click arrow event.target.closest(...) window
royxat — keydown arrow event.target window
filtrlar — click arrow event.target.closest(...) window
eksportTugma — click arrow eksportMatn window

Hammasi arrow, vazifalar.js esa oddiy skript. Strict mode darsida uning boshiga "use strict"; qo'shgan edik. Lekin u faqat funksiya ichidagi oddiy chaqiruvga ta'sir qiladi — skriptning yuqori darajasidagi this baribir window. Arrow esa aynan shu this ni oladi. Hech bir tinglovchida this yo'q — va bu to'g'ri.

Tajribada «Faol» bosilganda konsolda:

text
true
filtrlar / faol

Oddiy function da this — tinglovchi turgan div#filtrlar, bosilgan tugma emas. Bosilgan tugma — event.target. Delegation'da this bizga kerakli tugmani bermaydi, event.target.closest("[data-filtr]") esa beradi.

README.md ga, oxiriga:

markdown
## Kod qoidalari

- Hodisa tinglovchisi — arrow funksiya, parametri `event`.
- Tinglovchi turgan element — `event.currentTarget`,
  bosilgan element — `event.target.closest(...)`.
- Tinglovchilarda `this` ishlatilmaydi: arrow'da u `window`,
  delegation'da esa ota element bo'ladi.
bash
git add README.md
git commit -m "Docs: tinglovchilarda this o'rniga event qoidasini yoz"

Kod o'zgarmadi — sayt avvalgidek ishlaydi. Branch'ni hali main ga qo'shmang: keyingi ikki dars shu branch'da davom etadi.

Maslahat: Bu qaror faqat tinglovchilar uchun. Obyekt metodlarida this — oddiy va to'g'ri vosita. Klasslarni o'rganganda (class sintaksisi) u yana markazga chiqadi.

12. Real ishda

  • Intervyu. "this nimaga teng?" — JavaScript intervyusidagi eng mashhur savollardan. Odatda kod beriladi va har chaqiruvda this so'raladi. Javob — shu darsdagi sxema: arrow → new → call → nuqta → oddiy.
  • Eski kod. jQuery (2010-yillarning eng mashhur DOM kutubxonasi) va boshqa eski kutubxonalarda tinglovchi ichida this juda ko'p: $(this).hide(). Bunday kodni o'qiyotganda oddiy function ekanini tekshiring.
  • React. Eski React kodida (klass komponentlari) this.state, this.props va this.handleClick.bind(this) uchraydi. Zamonaviy React funksiyalar bilan yoziladi va this deyarli yo'q (React — 17-qismda).
  • Node. Modullarda yuqori darajadagi this — undefined. Eski CommonJS kodida this === module.exports dan foydalanadigan joylarni ham uchratasiz.

Xulosa

  • this funksiya yozilganda emas, chaqirilganda aniqlanadi.
  • To'rt qoida: new F() — yangi obyekt; f.call(x) — x; obj.f() — obj; oddiy f() — strict/modulda undefined, eski skriptda global obyekt.
  • Ustuvorlik shu tartibda: new > aniq > metod > oddiy.
  • Arrow'ning o'z this i yo'q: u yozilgan joydagi this ni oladi, call va thisArg uni o'zgartirmaydi, new bilan chaqirib bo'lmaydi.
  • Metod — shorthand bilan, metod ichidagi callback — arrow bilan.
  • Brauzer tinglovchida this — event.currentTarget. Zamonaviy kod this o'rniga event dan foydalanadi.

Keyingi dars: this yo'qolishi va uni tiklash — metodni callback sifatida uzatganda this nega yo'qolishini va uni qaytarishning uch usulini ko'ramiz.

Manbalar

  • MDN: "this" — developer.mozilla.org
  • MDN: "Arrow function expressions" — "Cannot be used as methods" bo'limi
  • ECMAScript 2025 Language Specification: "OrdinaryCallBindThis" — tc39.es/ecma262
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript this: to'rt qoida va arrow funksiya istisnosi — IlmHamroh