[ Web Proxy ]
URL:
Viewing: https://uz.javascript.info/bind [Back]  [Original]

Funktsiyani bog'lash
UZ

Ushbu ochiq manbali loyihani butun dunyo bo'ylab odamlar uchun taqdim etmoqchimiz.

Ushbu qo'llanmaning mazmuni sizning tilingizga tarjima qilishga yordam bering!

    Javascript.info saytidan qidirish:
    O'quv qo'llanmasidan qidiring:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    Obyekt usullari bilan setTimeout dan foydalanishda malum bir muammo yuzaga keladi: this ni yoqotish.

    Tosatdan, this togri ishlashni toxtatadi. Vaziyat yangi boshlanuvchilar uchun odatiy holdir, ammo tajribali dasturchilar bilan ham sodir boladi.

    this ni yoqotish

    Biz allaqachon bilamizki, JavaScript-da this ni yoqotish oson. Biror usulni obyektdan alohida joyga otkazgandan song this yoqoladi.

    Bu setTimeout bilan qanday sodir bolishi mumkin:

    let user = {
      firstName: "John",
      sayHi() {
        alert(`Salom, ${this.firstName}!`);
      }
    };
    
    setTimeout(user.sayHi, 1000); // Salom, undefined!

    Korib turganimizdek, chiqishda John this.firstName emas, balki undefined korsatilgan!

    Buning sababi, setTimeout obyektdan alohida user.sayHi funktsiyasini olgan. Oxirgi satrni quyidagicha yozish mumkin:

    let f = user.sayHi;
    setTimeout(f, 1000); // yo'qolgan foydalanuvchi konteksti

    Brauzer ichidagi setTimeout usuli biroz oziga xos: funktsiya chaqiruvi uchun this=window ni ornatadi (Node.js uchun this taymer obyekti boladi, lekin bu yerda muhim emas). Shunday qilib this.firstName uchun u mavjud bolmagan window.firstName ni olishga harakat qiladi. Korganimiz kabi boshqa shunga oxshash holatlarda odatda this undefined boladi.

    Vazifa odatiy holdir biz obyekt usulini boshqa joyda (bu yerda rejalashtiruvchiga) chaqirishni xohlaymiz. Qanday qilib togri kontekstda chaqirilishiga ishonch hosil qilish kerak?

    Yechim 1: oralgan funktsiya

    Oddiy yechim oralgan funktsiyasidan foydalanish:

    let user = {
      firstName: "John",
      sayHi() {
        alert(`Salom, ${this.firstName}!`);
      }
    };
    
    setTimeout(function() {
      user.sayHi(); // Salom, John!
    }, 1000);

    Endi u ishlaydi, chunki u user ni tashqi leksik muhitdan oladi va keyin odatdagi usulni chaqiradi.

    Xuddi shu, ammo qisqaroq:

    setTimeout(() => user.sayHi(), 1000); // Salom, John!

    Yaxshi korinadi, lekin bizning kod tuzilishimizda biroz zaiflik paydo boladi.

    setTimeout ishga tushirilgunga qadar nima sodir boladi (kechikish bir soniya!) ozgaruvchan user boshqa qiymatga ega boladimi? Keyin, tosatdan, u notogri obyektni chaqiradi!

    let user = {
      firstName: "John",
      sayHi() {
        alert(`Salom, ${this.firstName}!`);
      }
    };
    
    setTimeout(() => user.sayHi(), 1000);
    
    // ...1 soniya ichida
    user = { sayHi() { alert("setTimeout-da boshqa foydalanuvchi!"); } };
    
    // setTimeout-da boshqa foydalanuvchi?!?

    Keyingi yechim bunday narsa bolmasligini kafolatlaydi.

    Yechim 2: bind

    Funksiyalar this ni ornatishga imkon beradigan ornatilgan bind usulini taqdim etadi.

    Asosiy sintaksis:

    // murakkabroq sintaksis biroz keyinroq bo'ladi
    let boundFunc = func.bind(context);

    func.bind(context) ning natijasi funktsiya sifatida chaqiriladigan va shaffof ravishda func sozlamasini this=context ga otkazadigan ekzotik obyekt funktsiyasiga oxshash.

    Boshqa sozlar bilan aytganda, boundFunc chaqiruvi sobit this bilan func chaqiruviga oxshaydi.

    Masalan, bu erda funcUser chaqiruvni func ga this=user bilan amalga oshiradi:

    let user = {
      firstName: "John"
    };
    
    function func() {
      alert(this.firstName);
    }
    
    let funcUser = func.bind(user);
    funcUser(); // John

    Bu yerda func.bind(user) func ning boglangan varianti sifatida, sobit this=user bilan.

    Barcha argumentlar asl func ga uzatiladi, masalan:

    let user = {
      firstName: "John"
    };
    
    function func(phrase) {
      alert(phrase + ', ' + this.firstName);
    }
    
    // this ni user ga bog'lash
    let funcUser = func.bind(user);
    
    funcUser("Hello"); // Salom, John ("Salom" argumenti berilgan va this=user)

    Endi obyekt usuli bilan sinab koraylik:

    let user = {
      firstName: "John",
      sayHi() {
        alert(`Salom, ${this.firstName}!`);
      }
    };
    
    let sayHi = user.sayHi.bind(user); // (*)
    
    sayHi(); // Salom, John!
    
    setTimeout(sayHi, 1000); // Salom, John!

    (*) satrida biz user.sayHi usulini qollaymiz va uni user bilan boglaymiz. sayHi bu boglangan funktsiya, uni yakka ozi chaqirish yoki setTimeout ga otkazish mumkin bu muhim emas, kontekst togri boladi.

    Bu yerda argumentlar boricha berilganligini korishimiz mumkin, faqat this bind bilan ornatiladi:

    let user = {
      firstName: "John",
      say(phrase) {
        alert(`${phrase}, ${this.firstName}!`);
      }
    };
    
    let say = user.say.bind(user);
    
    say("Salom"); // Salom, John ("Salom" say ga bog'landi)
    say("Hayir"); // Hayir, John ("Hayir" say ga bog'landi)
    Qulaylik usuli: bindAll

    Agar obyekt juda kop usullarga ega bolsa va biz uni faol ravishda uzatishni rejalashtirmoqchi bolsak, unda biz ularni barchasini tsiklda birlashtirib boglashimiz mumkin:

    for (let key in user) {
      if (typeof user[key] == 'function') {
        user[key] = user[key].bind(user);
      }
    }

    JavaScript kutubxonalari, shuningdek, qulay ommaviy biriktirish uchun funktsiyalarni taqdim etadi, masalan, _.bindAll(obj) lodash-da.

    Xulosa

    func.bind(context, ... args) usuli this kontekstni tuzatuvchi va berilgan bolsa, birinchi argumentlarni func funktsiyasining boglangan variantini qaytaradi.

    Odatda biz this ni biron bir joyga otkazib yuborishimiz uchun bind ni obyekt usulida tuzatish uchun qollaymiz. Masalan, setTimeout ga. Zamonaviy dasturlashda bog'lash uchun koproq sabablar bor, biz ularni keyinroq uchratamiz.

    Vazifalar

    Chiqish qanday boladi?

    function f() {
      alert(this); // ?
    }
    
    let user = {
      g: f.bind(null),
    };
    
    user.g();
    yechim

    Javob: null.

    function f() {
      alert(this); // null
    }
    
    let user = {
      g: f.bind(null),
    };
    
    user.g();

    Boglangan funktsiya konteksti qatiy belgilangan. Buni yanada ozgartirishning iloji yoq.

    Shunday qilib, biz user.g() ni ishga tushirganimizda ham asl funktsiya this=null bilan chaqiriladi.

    Qoshimcha boglash orqali this ni ozgartira olamizmi?

    Chiqish qanday boladi?

    function f() {
      alert(this.name);
    }
    
    f = f.bind({ name: "John" }).bind({ name: "Ann" });
    
    f();
    yechim

    Javob: John.

    function f() {
      alert(this.name);
    }
    
    f = f.bind({ name: "John" }).bind({ name: "Pete" });
    
    f(); // John

    f.bind(...) tomonidan qaytarilgan ekzotik boglangan funktsiya obyekti kontekstni eslaydi (va argumentlar, agar taqdim etilsa) faqat yaratilish vaqtida.

    Funksiyani qayta boglab bolmaydi.

    muhimlik: 5

    Funksiya xususiyatida qiymat mavjud. U bind dan keyin ozgaradimi? Javobingizni asoslang.

    function sayHi() {
      alert( this.name );
    }
    sayHi.test = 5;
    
    let bound = sayHi.bind({
      name: "John"
    });
    
    alert( bound.test ); // chiqishi qanday bo'ladi? nega?
    yechim

    Javob: undefined.

    bind natijasi boshqa obyekt. U test xususiyatiga ega emas.

    muhimlik: 5

    Quyidagi koddagi askPassword() ga chaqiruv parolni tekshirishi kerak va keyin javobga qarab user.loginOk/loginFail chaqirishi kerak.

    Ammo bu xatoga olib keladi. Nima uchun?

    Hammasi togri ishlashni boshlashi uchun ajratilgan satrni togrilab qoying (boshqa satrlarni ozgartirish kerak emas).

    function askPassword(ok, fail) {
      let password = prompt("Password?", '');
      if (password == "rockstar") ok();
      else fail();
    }
    
    let user = {
      name: 'John',
    
      loginOk() {
        alert(`${this.name} logged in`);
      },
    
      loginFail() {
        alert(`${this.name} failed to log in`);
      },
    
    };
    
    askPassword(user.loginOk, user.loginFail);
    yechim

    Xato yuz berdi, chunki ask obyektsiz loginOk/loginFail funktsiyalarini oladi.

    Ularni chaqirganda, ular tabiiy ravishda this=undefined deb taxmin qilishadi.

    Keling, kontekstni boglaymiz:

    function askPassword(ok, fail) {
      let password = prompt("Password?", '');
      if (password == "rockstar") ok();
      else fail();
    }
    
    let user = {
      name: 'John',
    
      loginOk() {
        alert(`${this.name} logged in`);
      },
    
      loginFail() {
        alert(`${this.name} failed to log in`);
      },
    
    };
    
    askPassword(user.loginOk.bind(user), user.loginFail.bind(user));

    Endi u ishlaydi.

    Muqobil yechim bolishi mumkin:

    //...
    askPassword(
      () => user.loginOk(),
      () => user.loginFail()
    );

    Odatda bu ham ishlaydi, lekin user sorash va ishga tushirish vaqtlari orasida yozilishi mumkin bolgan murakkab vaziyatlarda ishlamay qolishi mumkin () => user.loginOk ().

    Its a bit less reliable though in more complex situations where user variable might change after askPassword is called, but before the visitor answers and calls () => user.loginOk().

    Vazifa this yo'qotishni so'rang ning biroz murakkab variantidir.

    user obyekti ozgartirildi. Endi ikkita funktsiya loginOk/loginFail orniga, unda bitta user.login(true/false) funktsiyasi mavjud.

    Quyidagi kodda askPassword-ni user.login(true) ok va user.login(false) fail deb chaqirishi uchun nima qilish kerak?

    function askPassword(ok, fail) {
      let password = prompt("Password?", '');
      if (password == "rockstar") ok();
      else fail();
    }
    
    let user = {
      name: 'John',
    
      login(result) {
        alert( this.name + (result ? ' logged in' : ' failed to log in') );
      }
    };
    
    askPassword(?, ?); // ?

    Siz faqat ajratilgan qismni ozgartirishiz kerak.

    yechim
    1. Yoki orash funktsiyasidan foydalaning, qisqacha bolishi uchun oq:

      askPassword(
        () => user.login(true),
        () => user.login(false)
      );

      Endi u tashqi ozgaruvchanlardan user oladi va odatdagi usulda ishlaydi.

    2. Yoki user ni kontekst sifatida ishlatadigan va togri birinchi argumentga ega bolgan user.login dan qisman funktsiya yarating:

      askPassword(user.login.bind(user, true), user.login.bind(user, false));
    O'quv qo'llanma xaritasi

    Izohlar

    izoh berishdan oldin buni o'qing
    • Agar sizda nimani yaxshilash kerakligi haqida takliflaringiz bo'lsa - iltimos, GitHub muammosini yuboring yoki izoh berish o'rniga so'rov yuboring.
    • Agar siz maqolada biror narsani tushunolmasangiz - iltimos, batafsilroq ma'lumot bering.
    • Bir nechta so'z so'zlarini kiritish uchun <code> yorlig'ini ishlating, bir nechta satrlar uchun - ularni <pre> yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page