this
this nima, V8 ichida qanday ishlaydi, 4 ta qoida (implicit, losing, explicit, new), arrow function ning this mexanizmi.
17-dars
this
Ko'pchilik this ni "o'zini o'zi ko'rsatadi" deb o'ylaydi. Bu noto'g'ri.
this — funksiya chaqirilgan paytdagi kontekst. U funksiya qayerda yozilganiga emas, qayerdan chaqirilganiga qarab belgilanadi.
Bu — Lexical Scope ning teskarisi:
| Qayerga qaraydi | Qachon belgilanadi | |
|---|---|---|
| Lexical Scope | Yozilgan joy | Parse vaqtida |
| this | Chaqirilgan joy | Runtime da, har chaqiruvda |
V8 ichida this qanday ishlaydi
Har bir Execution Context ichida ThisBinding degan slot bor:
Execution Context {
LexicalEnvironment: { ... }
ThisBinding: ??? ← this shu yerda saqlanadi
}
Funksiya chaqirilganda V8 qanday chaqirilganiga qarab ThisBinding ni belgilaydi. Bu qoidalar qat'iy — 4 ta asosiy holat bor.
4 ta qoida
Qoida 1 — Implicit Binding (metod sifatida chaqirilganda)
const user = {
name: 'Ali',
greet() {
console.log(this.name);
}
};
user.greet(); // 'Ali'
Qoida: Funksiya nuqta orqali chaqirilsa — nuqtadan chap tomondagi obyekt this bo'ladi.
user.greet()
↑
shu obyekt → this = user
V8 ichida:
Execution Context: greet
ThisBinding: user ← nuqtadan chapni oldi
Qoida 2 — Implicit yo'qolishi (Losing this)
Bu eng ko'p uchraydigan xato:
const user = {
name: 'Ali',
greet() {
console.log(this.name);
}
};
const fn = user.greet; // metodni olib chiqdik
fn(); // undefined
Nima bo'ldi?
user.greet — funksiyaning o'zini oldik, lekin user bilan bog'liqlikni uzib oldik. Endi fn() chaqirilganda nuqtadan chap tomonda hech narsa yo'q:
fn() → this = global (sloppy mode) / undefined (strict mode)
user.greet() → this = user
Yana bir klassik holat — callback:
const user = {
name: 'Ali',
greet() {
setTimeout(function() {
console.log(this.name); // undefined
}, 100);
}
};
user.greet();
setTimeout ga berilgan funksiya — oddiy funksiya sifatida chaqiriladi, Context yo'q, this yo'qoladi.
Qoida 3 — Explicit Binding (call, apply, bind)
this ni qo'lda belgilash:
function greet() {
console.log(this.name);
}
const user = { name: 'Ali' };
greet.call(user); // 'Ali' — darhol chaqiradi
greet.apply(user); // 'Ali' — darhol chaqiradi
const boundGreet = greet.bind(user);
boundGreet(); // 'Ali' — yangi funksiya qaytaradi
V8 ichida call/apply chaqirilganda:
Execution Context: greet
ThisBinding: user ← birinchi argument dan olindi
Qoida 4 — new Binding
function Person(name) {
this.name = name;
console.log(this); // Person { name: 'Ali' }
}
const p = new Person('Ali');
new bilan chaqirilganda V8:
- Bo'sh obyekt yaratadi:
{} ThisBinding= shu yangi obyekt- Konstruktor ishlaydi —
this.name = 'Ali'→ yangi obyektga yoziladi - Yangi obyektni qaytaradi
Qoidalar prioriteti
Bir vaqtda bir nechta qoida to'qnashsa — qaysi biri ustun?
new > bind/call/apply > nuqta (implicit) > global/undefined
function foo() { console.log(this.x); }
const obj = { x: 10 };
const bound = foo.bind(obj);
new bound(); // undefined — new, bind dan ustun
bound(); // 10 — bind ishlaydi
Arrow Function va this — butunlay boshqa mexanizm
Arrow function — o'zining this i yo'q.
Bu shunchaki "boshqacha this" emas — arrow function Execution Context yaratilganda ThisBinding umuman bo'lmaydi. U this ni o'qishga urinsa, Lexical Scope bo'ylab yuqoriga chiqadi va birinchi topgan this ni oladi.
const user = {
name: 'Ali',
greet() {
// Bu oddiy funksiya — this = user
const inner = () => {
console.log(this.name); // 'Ali'
// this yo'q, yuqoriga chiqdi → greet() ning this ini oldi → user
};
inner();
}
};
user.greet(); // 'Ali'
Oddiy funksiya bo'lganda:
const user = {
name: 'Ali',
greet() {
const inner = function() {
console.log(this.name); // undefined
// this bor, lekin inner() nuqtasiz chaqirildi → global/undefined
};
inner();
}
};
user.greet(); // undefined
V8 ichida Arrow Function ning this si
Oddiy funksiya:
Execution Context: greet
ThisBinding: user ← bor, qoida bo'yicha belgilandi
[[Environment]] → Global Execution Context (parent)
Arrow funksiya:
Execution Context: inner (arrow)
[[Environment]]: → greet ning LexicalEnvironment'iga pointer
ThisBinding: — ← YO'Q, umuman yaratilmadi
inner ichida this o'qilganda V8:
innerning Execution Context daThisBindingbormi? — yo'q[[Environment]]orqali yuqoriga:greetning Execution Context daThisBindingbormi? — bor,userthis = user
Bu — this ning lexical ishlashi. Arrow funksiya this ni ham Lexical Scope orqali topadi.
Amaliy — qayerda arrow, qayerda oddiy funksiya
Arrow funksiya kerak — callback ichida this ni saqlash:
class Timer {
constructor() {
this.seconds = 0;
}
start() {
setInterval(() => {
this.seconds++; // this = Timer instance — to'g'ri
console.log(this.seconds);
}, 1000);
}
}
const t = new Timer();
t.start(); // 1, 2, 3...
Oddiy funksiya bo'lganda this.seconds undefined bo'lardi.
Arrow funksiya KERAK EMAS — metod sifatida:
const user = {
name: 'Ali',
greet: () => {
console.log(this.name); // undefined!
}
};
user.greet(); // undefined
Nima bo'ldi? Arrow funksiya yaratilganda [[Environment]] ga qaraydi — bu yerda user obyektining ichida yozilyapti. Lekin obyekt {} yangi scope yaratmaydi — faqat funksiyalar va bloklar scope yaratadi. Shuning uchun arrow funksiya global scope ning this ini oladi.
user = { greet: arrow }
Arrow yaratilganda atrofidagi scope → global scope
this → global (browser da window, strict da undefined)
Umumiy qoida — qachon arrow, qachon oddiy
| Holat | Qaysi funksiya | Sabab |
|---|---|---|
| Obyekt metodi | Oddiy | this = obyekt bo'lishi kerak |
| Callback (setTimeout, map, filter) | Arrow | Tashqi this ni saqlash |
Constructor (new bilan) |
Oddiy | Arrow new bilan ishlamaydi |
| Event handler (DOM) | Oddiy yoki arrow — vaziyatga qarab | Oddiy → this = element; Arrow → tashqi this |
| Class metodi ichidagi callback | Arrow | Class ning this ini saqlash |