Funksiyalar bilan chuqur ishlash

Funksiya bog'lash (bind)

Obyekt metodini alohida uzatganimizda โ€” masalan, setTimeoutga yoki hodisa (event) ishlovchisiga โ€” this yo'qoladi. Ushbu darsda bu klassik muammoni va uni bind orqali hal qilishni o'rganamiz.

this yo'qolishi muammosi

Obyekt metodini bir joyga uzatib, keyin boshqa kontekstda chaqirsak โ€” this asl obyektga emas, boshqa qiymatga ishora qiladi. Klassik misol โ€” metodni setTimeoutga uzatish:

let user = {
  ism: "Ali",
  salom() {
    console.log("Salom, " + this.ism);
  }
};

// this yo'qoladi:
setTimeout(user.salom, 1000);
// Natija: Salom, undefined
// (chunki setTimeout metodni obyektdan "ajratib" chaqiradi)

Nima uchun shunday bo'ladi? Chunki setTimeout user.salom funksiyasini oladi, lekin user obyektidan uzilgan holda. Chaqirilganda esa this mavjud emas (yoki brauzerda window) bo'lib qoladi.

Muammoning mohiyati: JavaScript'da this funksiya qanday e'lon qilinishiga emas, qanday chaqirilishiga bog'liq. user.salom() chaqirilsa this โ€” user; alohida func() chaqirilsa โ€” yo'q.

Vaqtinchalik yechim: o'ram

Eng oddiy yechim โ€” funksiyani o'rovchi (wrapper) funksiyaga o'rab uzatish:

let user = {
  ism: "Ali",
  salom() {
    console.log("Salom, " + this.ism);
  }
};

setTimeout(function() {
  user.salom(); // this endi to'g'ri โ€” user
}, 1000);
// Natija: Salom, Ali
Bu yechim ishlaydi, lekin nozik xatosi bor: agar setTimeout ishga tushguncha user o'zgartirilsa (masalan user = boshqaObyekt), o'ram yangi qiymatni ishlatadi. bind esa qiymatni bog'lanish vaqtida qat'iy mahkamlaydi.

func.bind โ€” kontekstni mahkamlash

bind metodi thisni qat'iy bog'langan yangi funksiyani qaytaradi. Sintaksisi:

let bog_langan = func.bind(context);

Natijadagi bog_langan โ€” bu func bilan bir xil funksiya, lekin uning thisi doimo context bo'ladi, qanday chaqirilishidan qat'i nazar:

bind-asosiy.js
// natija shu yerda chiqadi

Endi setTimeout muammosi ham osongina hal bo'ladi โ€” bog'langan funksiyani uzatamiz:

let salomBer = user.salom.bind(user);
setTimeout(salomBer, 1000);
// Natija: Salom, Ali โ€” this yo'qolmaydi
Agar bir obyektning bir nechta metodini bog'lash kerak bo'lsa, ularni siklda aylanib obj[key] = obj[key].bind(obj) qilish mumkin. Ba'zi kutubxonalar (masalan React'ning eski kodi) shu naqshni ko'p ishlatgan.

Qisman qo'llash (partial application)

bind nafaqat thisni, balki argumentlarni ham oldindan mahkamlashi mumkin. Bu qisman qo'llash (partial application) deb ataladi:

let bog_langan = func.bind(context, arg1, arg2, ...);

Argumentlardan bir qismini oldindan belgilab, faqat qolganini keyin uzatiladigan yangi funksiya olamiz:

partial-application.js
// natija shu yerda chiqadi

Bu texnika mavjud umumiy funksiyadan aniqroq, ixtisoslashgan funksiyalar yasashda juda foydali. Masalan, send(from, to, text) dan sendTo(text) yasab, from va toni oldindan belgilash mumkin:

partial-yuborish.js
// natija shu yerda chiqadi
Argumentlar chapdan o'ngga mahkamlanadi. Ya'ni bind birinchi argumentlarni belgilaydi, keyin chaqiruv paytida berilganlar ularning davomiga qo'shiladi.

bind haqida muhim jihatlar

bind-name.js
// natija shu yerda chiqadi
func.bind(user1).bind(user2) โ€” ikkinchi bind ta'sir qilmaydi! this baribir user1 bo'lib qoladi. Bog'lanish qaytarilmaydi.

Xulosa