Մենք գիտենք, որ JavaScript ծրագրավորման լեզվում this-ի արժեքը որոշվում է ոչ թե ֆունկցիայի ստեղծման՝ այլ կանչի ժամանակ: Այս առանձնահատկության շնորհիվ JavaScript-ը տարբերվում է մի շարք այլ դասական ծրագրավորման լեզուներից։ Նաև ծանոթ ենք, որ JavaScript-ում ֆունկցիաները հանդիսանում են օբյեկտներ, որոնք ինչ-որ գործողություն են կատարում, և կարող են ունենալ հատկություններ՝ ինչպես սովորական օբյեկտների դեպքում էր։ Իսկ եթե ֆունկցիաները հանդիսանում են օբյեկտներ և ունեն հատկություններ, նրանք կարող են ունենալ նաև մեթոդներ։ Ծանոթանանք ֆունկցիաների ներդրված մեթոդներից մեկի՝ bind-ի հետ, որը հիմնականում օգտագործվում է this-ը ֆունկցիայի հետ շաղկապելու համար (Ի՞նչու հիմնականում, որովհետև այլ կիրառություն նույնպես ունի՝ երբեմն bind-ի օգնությամբ ստեղծում են ֆիքսված արգումենտներով ֆունկցիաներ)։ Մինչ bind մեթոդին ծանոթանալը՝ կարդացեք this-ի և ֆունկցիաների օբյեկտներ հանդիսանալու մասին:
this-ին նվիրված գրառման մեջ մենք արդեն տեսել ենք JavaScript-ում ազատ this-ի կոնցեպտի «տարօրինակ» հետևանքները։
"use strict";
const person = {
firstName: "John",
lastName: "Smith",
sayHello: function () {
alert("hello " + this.firstName + " " + this.lastName);
},
};
person.sayHello(); // hello John Smith
Ունենք person օբյեկտը, որի մեջ գտնվող sayHello մեթոդի կանչը alert է անում person-ին ուղղված ողջույնի խոսքը։ Ինչպես գիտենք մեթոդի սինթաքսը օգտագործելու ժամանակ this-ի արժեքը միշտ լինում է կետից առաջ գտնվող օբյեկտը։ Սակայն եթե այժմ մենք person օբյեկտի sayHello մեթոդը վերագրենք մեկ այլ փոփոխականի և փորձենք կանչել այդ փոփոխականի օգնությամբ, this-ի արժեքը այլևս չի լինի person օբյեկտը։ Այսինքն չնայած, որ sayHello մեթոդը ստեղծվել է person օբյեկտի մեջ և պատկանում է person օբյեկտին, դա ոչ մի երաշխիք չի տալիս մեզ, որ this-ի արժեքը միշտ լինելու է person օբյեկտը։
"use strict";
const greeting = person.sayHello;
greeting(); // Uncaught TypeError
Ինչպես տեսնում ենք greeting ֆունկցիայի կանչը առաջացնում է սխալ։ Երբ կոնսոլում կարդում ենք սխալի նկարագրությունը՝ տեսնում ենք սխալն առաջացել է, որովհետև this-ի արժեքը undefined է։ Որպեսզի this-ի արժեքը միշտ հղվի այն օբյեկտին, որի մեջ ստեղծվել է մեթոդը, մենք կարող ենք օգտագործել ֆունկցիաների bind մեթոդը։
const greeting = person.sayHello.bind(person);
greeting(); // hello John Smith
Մենք person օբյեկտի sayHello մեթոդի վրա ֆունկցիաների bind մեթոդի օգնությամբ ֆիքսում ենք person օբյեկտը որպես this-ի արժեք։ Այն վերադարձնում է նոր ֆունկցիա՝ greeting-ը, որի կանչը միշտ վերահասցեավորվում է sayHello մեթոդի կանչին՝ person օբյեկտի կոնտեքստում։
Պետք է հիշել, որ բոլոր այն դեպքերում, երբ մեթոդն անմիջապես օբյեկտի վրայից չի կանչվում, տեղի է ունենում this-ի կորուստ։ Քննարկենք մեկ այլ իրադրություն, երբ օբյեկտի մեթոդն օգտագործվում է որպես հետադարձ կանչի ֆունկցիա, այսինքն որպես արգումենտ տրվում է մեկ այլ ֆունկցիայի։ Օրինակ փորձենք օբյեկտի մեթոդը որպես արգումենտ հաղորդել setTimeout ֆունկցիային։
setTimeout(person.sayHello, 1000);
Աշխատեցնելով կոդը, մի վայրկայնից alert-ի պատուհանում կտեսնենք hello undefined undefined արտահայտությունը։ Այսինքն person.sayHello մեթոդն այլևս չի հղվում person օբյեկտին։ Այն ճիշտ է՝ ստեղծվել է person օբյեկտի մեջ, բայց նրա this-ի արժեքը այժմ person-ը չէ, որովհետև նրա կանչը տեղի է ունենում գլոբալ կոնտեքստում և հետևաբար նրա this-ը այժմ անորոշ է՝ undefined (Ոչ խիստ ռեժիմում՝ window կամ Object [global] կախված միջավայրից)։
Այժմ փորձենք bind մեթոդի օգնությամբ person օբյեկտը ֆիքսել, շաղկապել sayHello մեթոդի վրա, որպեսզի setTimeout ֆունկցիայի կանչը վերադարձնի կոռեկտ արդյունք։
setTimeout(person.sayHello.bind(person), 1000);
Աշխատեցնելով կոդը, մի վայրկյանից alert-ի պատուհանում կտեսնենք hello John Smith: Որպեսզի կոդն ավելի պարզ և ընթեռնելի դարձնենք, մենք կարող ենք վերևի արտահայտությունը կիսել երկու մասի՝ շաղկապած (կամ բայնդինգ արած) մեթոդը վերագրելով ուրիշ փոփոխականի, և ապա նոր որպես արգումենտ հաղորդելով setTimeout ֆունկցիային։
const sayHello = person.sayHello.bind(person);
setTimeout(sayHello, 1000); // hello John Smith
Ի դեպ bind մեթոդը JavaScript-ում առկա է դեռևս ES5 ստանդարտի ժամանակներից և հասկանալի է բոլոր ժամանակակից ցանցային դիտարկիչներին (նույնիսկ Internet Explorer-ին՝ սկսած 9-րդ տարբերակից)։