Про що слід знати this
this
(він же "контекст") - це спеціальне ключове слово всередині кожної функції, і його значення залежить лише від того, як функція викликалася, а не як / коли / де вона була визначена. На неї не впливають лексичні області, як і інші змінні (крім функцій стрілок, див. Нижче). Ось кілька прикладів:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Щоб дізнатися більше про this
це, ознайомтеся з документацією MDN .
Як посилатися на правильне this
Не використовуйте this
Ви фактично не хочете отримати доступ this
зокрема, але об’єкт, на який він посилається . Ось чому легким рішенням є просто створити нову змінну, яка також посилається на цей об’єкт. Змінна може мати будь-яке ім'я, але поширеними є self
і that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Оскільки self
це звичайна змінна, вона підпорядковується лексичним правилам області застосування та є доступною всередині зворотного дзвінка. Це також має перевагу в тому, що ви можете отримати доступ до this
значення самого зворотного дзвінка.
Явно встановлений this
зворотний дзвінок - частина 1
Це може здатися, що ви не маєте контролю над значенням, this
оскільки його значення встановлюється автоматично, але це насправді не так.
Кожна функція має метод .bind
[docs] , який повертає нову функцію з this
прив’язкою до значення. Функція має точно таку саму поведінку, як та, яку ви викликали .bind
, лише та, this
яку ви встановили. Незалежно від того, як або коли ця функція викликається, this
завжди буде посилатися на передане значення.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
У цьому випадку ми прив'язуємо зворотний виклик this
до значення MyConstructor
s this
.
Примітка: Прив'язуючи контекст для jQuery, використовуйте замість нього jQuery.proxy
[docs] . Причиною цього є те, що вам не потрібно зберігати посилання на функцію під час від'єднання зворотного виклику події. jQuery обробляє це внутрішньо.
ECMAScript 6 представляє функції стрілок , які можна розглядати як лямбда-функції. Вони не мають власної this
прив'язки. Натомість this
шукається в області застосування, як звичайна змінна. Це означає, що вам не потрібно дзвонити .bind
. Це не єдина особлива поведінка у них, будь ласка, зверніться до документації MDN для отримання додаткової інформації.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Набір this
зворотного дзвінка - частина 2
Деякі функції / методи, які приймають зворотні дзвінки, також приймають значення, до якого this
слід звернутися. Це в основному те саме, що зв’язувати його самостійно, але функція / метод робить це за вас. Array#map
[docs] - такий метод. Його підпис:
array.map(callback[, thisArg])
Перший аргумент - це зворотний виклик, а другий аргумент - значення, на яке this
слід посилатися. Ось надуманий приклад:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Примітка: Якщо ви можете передавати значення this
чи ні, зазвичай згадується в документації цієї функції / методу. Наприклад, метод jQuery [docs]$.ajax
описує параметр, який називається context
:
Цей об'єкт стане контекстом усіх зворотних викликів, пов'язаних з Ajax.
Поширена проблема: використання об'єктних методів як зворотних дзвінків / обробників подій
Іншим поширеним проявом цієї проблеми є те, коли метод об'єкта використовується як обробник викликів / подій. Функції є громадянами першого класу в JavaScript, а термін "метод" - це просто розмовний термін для функції, яка є значенням властивості об'єкта. Але ця функція не має конкретного посилання на об'єкт, що "містить".
Розглянемо наступний приклад:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
Функція this.method
призначається як обробник подій клацання, але якщо document.body
натиснуто на, значення буде зареєстровано undefined
, оскільки всередині обробника подій this
відноситься до document.body
, а не до екземпляра Foo
.
Як вже було сказано на початку, те, що this
стосується, залежить від того, як функція викликається , а не як вона визначається .
Якщо код виглядав наступним чином, може бути більш очевидним, що функція не має неявного посилання на об'єкт:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
Рішення таке ж, як згадувалося вище: Якщо доступно, використовуйте .bind
для явного прив’язки this
до конкретного значення
document.body.onclick = this.method.bind(this);
або явно викликати функцію як "метод" об'єкта, використовуючи анонімну функцію як обробник виклику / події та призначити об'єкт ( this
) іншій змінній:
var self = this;
document.body.onclick = function() {
self.method();
};
або скористайтеся функцією стрілки:
document.body.onclick = () => this.method();