bind, apply va call bir-biridan nimasi bilan farq qiladi?

MiddleJavaScript #javascript #this #bind-apply-call

Savol

bind, apply va call metodlari bir-biridan nimasi bilan farq qiladi va qaysi birini qachon ishlatish kerak?

Qisqa javob

Uchalasi ham funksiyani chaqirishda this qiymatini aniq belgilashga imkon beradi, lekin har xil tarzda: call va apply funksiyani darhol chaqiradi (farqi faqat argumentlarni uzatish formatida — vergul bilan yoki massiv sifatida), bind esa funksiyani chaqirmaydi, balki this'i doimiy biriktirilgan yangi funksiya qaytaradi.

Batafsil javob

  • call(thisArg, arg1, arg2, ...) — funksiyani darhol, ko'rsatilgan this va birma-bir sanab o'tilgan argumentlar bilan chaqiradi.
  • apply(thisArg, [arg1, arg2, ...]) — call bilan bir xil ishni bajaradi, faqat argumentlar yagona massiv sifatida uzatiladi. Argumentlar allaqachon massivga yig'ilgan bo'lsa yoki ularning soni oldindan noma'lum bo'lsa, qulay.
  • bind(thisArg, arg1, ...) — funksiyani chaqirmaydi. Buning o'rniga this'i (va ixtiyoriy ravishda argumentlarning bir qismi — qisman qo'llash/partial application) doimiy mahkamlangan yangi funksiya qaytaradi; bu qiymatlarni hatto uning ustidan qayta call/apply chaqirilsa ham o'zgartirib bo'lmaydi.

Amaliy qoida: call/apply — hozir, to'g'ridan-to'g'ri kerakli kontekst bilan bir martalik chaqiruv uchun; bind — funksiyani kelajakda biror joyga (hodisa handleri, callback) uzatish kerak bo'lganda, lekin this kafolatlangan holda to'g'ri bo'lishi kerak bo'lganda.

Muhim nuans: agar bind/call/apply strelka funksiyasiga qo'llansa — ular this'ga hech qanday ta'sir ko'rsatmaydi, chunki strelka funksiyalarining o'zining qayta belgilash mumkin bo'lgan this'i yo'q (this va strelka funksiyalari haqidagi savolga qarang).

Misol

const user = {
  name: 'Alice',
  greet(greeting, punctuation) {
    console.log(`${greeting}, ${this.name}${punctuation}`)
  }
}

const otherUser = { name: 'Bob' }

// call — argumentlar vergul bilan, chaqiruv darhol
user.greet.call(otherUser, 'Salom', '!') // "Salom, Bob!"

// apply — argumentlar massiv sifatida, chaqiruv darhol
user.greet.apply(otherUser, ['Salom', '!']) // "Salom, Bob!"

// bind — yangi funksiya qaytaradi, chaqiruv keyinga qoldiriladi
const greetBob = user.greet.bind(otherUser, 'Salom')
greetBob('!') // "Salom, Bob!" — keyinroq chaqiriladi, this allaqachon mahkamlangan

// bind ishlatishning odatiy holati — hodisa handleri
class Counter {
  count = 0
  increment() {
    this.count++
  }
}

const counter = new Counter()
// bind bo'lmasa, bosilganda increment ichidagi this undefined/button bo'ladi
button.addEventListener('click', counter.increment.bind(counter))

Qo'shimcha savollar

  • Nega allaqachon biriktirilgan funksiya ustidan qayta bind chaqirish uning this'ini o'zgartira olmaydi?
  • O'zingizning bind'ingizni yopilish (closure) orqali qanday amalga oshirish mumkin?
  • Function.prototype.apply argumentlar soni o'zgaruvchan bo'lgan funksiyani chaqirishda nima uchun qulay (masalan, Math.max(...array) va Math.max.apply(null, array))?