Пошук уроків, статей та іншого контенту
Розберете, що означає this і чому його значення визначається способом виклику функції, а не місцем її оголошення.
thisthis — спеціальне ключове слово JavaScript, яке посилається на об’єкт, пов’язаний із поточним викликом функції.
На відміну від параметрів або локальних змінних, значення this зазвичай не визначається під час оголошення функції. Воно залежить від способу виклику функції.
function showThis() {
console.log(this);
}
showThis();Що саме буде виведено, залежить від режиму виконання та середовища. Важливіше запам’ятати принцип:
Для звичайної функції значення
thisвизначається способом її виклику.
this під час виклику як методуЯкщо функція викликається через об’єкт, то this посилається на цей об’єкт.
const user = {
name: "Олена",
sayHello() {
console.log(`Привіт! Мене звати ${this.name}.`);
}
};
user.sayHello();Результат:
Привіт! Мене звати Олена.У виразі:
user.sayHello();об’єкт перед крапкою — user. Саме він стає значенням this.
Одна й та сама функція може мати різне значення this залежно від того, як її викликати.
const user = {
name: "Олена",
sayHello() {
console.log(this.name);
}
};
user.sayHello(); // Олена
const greet = user.sayHello;
greet(); // undefined у строгому режиміПід час першого виклику функція викликається як метод:
user.sayHello();Тому this — це user.
Під час другого виклику функція зберігається в окремій змінній:
greet();Тепер вона викликається без об’єкта, тому зв’язок із user втрачено.
this у звичайній функціїРозглянемо приклад зі строгою модою:
"use strict";
function showThis() {
console.log(this);
}
showThis(); // undefinedУ строгому режимі під час звичайного виклику функції this дорівнює undefined.
Без строгого режиму в браузері старий варіант JavaScript міг підставляти глобальний об’єкт window. У Node.js та інших середовищах поведінка може відрізнятися, тому краще не покладатися на такий неявний режим.
Для передбачуваної поведінки використовуйте строгий режим або сучасний JavaScript-модуль.
this у вкладених функціяхВкладена звичайна функція не успадковує this зовнішнього методу.
"use strict";
const user = {
name: "Олена",
showName() {
function printName() {
console.log(this);
}
printName();
}
};
user.showName(); // undefinedМетод showName викликається через user, тому всередині showName значення this — це user.
Але printName викликається окремо:
printName();Тому її this — undefined.
thisСтрілкові функції працюють інакше. Вони не створюють власного this. Замість цього вони використовують this із зовнішнього контексту.
const user = {
name: "Олена",
showName() {
const printName = () => {
console.log(this.name);
};
printName();
}
};
user.showName(); // ОленаСтрілкова функція printName не отримує власного this. Вона використовує this методу showName, а в ньому this — це user.
Не варто створювати методи об’єктів як стрілкові функції, якщо метод має використовувати this.
const user = {
name: "Олена",
sayHello: () => {
console.log(this.name);
}
};
user.sayHello(); // undefinedСтрілка не отримує this від об’єкта user. Вона бере this із зовнішнього контексту, де властивості name може не бути.
Правильніше використати звичайний метод:
const user = {
name: "Олена",
sayHello() {
console.log(this.name);
}
};
user.sayHello(); // ОленаthisJavaScript має методи, за допомогою яких можна явно вказати значення this для звичайної функції:
call;
apply;
bind.
callcall викликає функцію одразу. Перший аргумент стає значенням this.
function introduce(city) {
console.log(`Мене звати ${this.name}. Я живу в місті ${city}.`);
}
const user = {
name: "Олена"
};
introduce.call(user, "Львів");Результат:
Мене звати Олена. Я живу в місті Львів.Тут this усередині introduce — це об’єкт user.
applyapply працює подібно до call, але аргументи передаються масивом.
function introduce(city, profession) {
console.log(`${this.name}: ${profession} з міста ${city}.`);
}
const user = {
name: "Олена"
};
introduce.apply(user, ["Львів", "розробниця"]);bindbind не викликає функцію одразу. Він створює нову функцію, у якої this уже прив’язаний до вказаного об’єкта.
const user = {
name: "Олена"
};
function sayHello() {
console.log(`Привіт, ${this.name}!`);
}
const boundSayHello = sayHello.bind(user);
boundSayHello();Результат:
Привіт, Олена!Це корисно, коли функцію потрібно передати як callback, але вона має зберегти зв’язок із конкретним об’єктом.
this у конструкторахПід час виклику функції з оператором new JavaScript створює новий об’єкт. Усередині функції-конструктора this посилається на цей новий об’єкт.
function User(name) {
this.name = name;
}
const user = new User("Олена");
console.log(user.name); // ОленаВиклик:
new User("Олена");створює об’єкт і встановлює його як this усередині User.
У сучасному JavaScript для цього часто використовують класи:
class User {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Привіт! Мене звати ${this.name}.`);
}
}
const user = new User("Олена");
user.sayHello();У конструкторі this — це новий екземпляр класу.
Розглянемо повний приклад, де метод змінює властивість об’єкта через this.
"use strict";
const counter = {
value: 0,
increment() {
this.value += 1;
},
show() {
console.log(`Поточне значення: ${this.value}`);
}
};
counter.show();
counter.increment();
counter.increment();
counter.show();Результат:
Поточне значення: 0
Поточне значення: 2Під час виклику:
counter.increment();this посилається на counter, тому вираз:
this.value += 1;збільшує саме counter.value.
thisПеред виконанням коду поставте запитання: як саме викликається функція?
object.method();this — це object.
functionName();У строгому режимі this — undefined.
call або applyfunctionName.call(object);
functionName.apply(object);this — це об’єкт, переданий першим аргументом.
bindconst newFunction = functionName.bind(object);
newFunction();this — це об’єкт, переданий у bind.
newnew Constructor();this — новий створений об’єкт.
Стрілкова функція не має власного this, а використовує його із зовнішнього контексту.
this визначається місцем оголошенняconst user = {
name: "Олена",
sayHello() {
console.log(this.name);
}
};
const anotherFunction = user.sayHello;
anotherFunction();Функція була оголошена всередині user, але це не означає, що this завжди буде user.
Значення має спосіб виклику:
user.sayHello(); // this — user
anotherFunction(); // this — не userthis у callbackconst user = {
name: "Олена",
sayHello() {
console.log(this.name);
}
};
setTimeout(user.sayHello, 1000);Метод передано як звичайну функцію, тому після виконання callback він не обов’язково матиме this, що посилається на user.
Для збереження контексту можна використати bind:
setTimeout(user.sayHello.bind(user), 1000);Або стрілкову функцію:
setTimeout(() => user.sayHello(), 1000);const counter = {
value: 0,
increment: () => {
this.value += 1;
}
};Така стрілка не має власного this, тому вона не працює як звичайний метод об’єкта.
Правильний варіант:
const counter = {
value: 0,
increment() {
this.value += 1;
}
};this і назвою змінноїthis не означає «поточна змінна» або «об’єкт, у якому написана функція». Це спеціальне значення, яке залежить від виклику функції.
const firstUser = {
name: "Олена",
showName() {
console.log(this.name);
}
};
const secondUser = {
name: "Андрій",
showName: firstUser.showName
};
secondUser.showName(); // АндрійФункція написана в контексті firstUser, але викликається через secondUser. Тому this — це secondUser.
this посилається на об’єкт, пов’язаний із викликом функції.
У виклику object.method() значення this — object.
У звичайному виклику функції в строгому режимі this дорівнює undefined.
Якщо передати метод окремо, він може втратити зв’язок із початковим об’єктом.
Стрілкові функції не мають власного this.
call, apply і bind дають змогу явно встановити this для звичайної функції.
Під час виклику через new this посилається на новий об’єкт.
Щоб визначити значення this, насамперед подивіться на спосіб виклику функції.