Ключевое слово this
Специальное слово в языке JavaScript, которое позволяет методам объектов и функциям получить доступ к информации внутри объекта.
Что же значит this
? В коде это слово заменяет имя объекта, информацию из которого мы пытаемся получить. В зависимости от того, какой объект вызывает метод, будет меняться и значение this
.
Давайте рассмотрим пример. Создадим объект user
с данными пользователя:
let user = {
name: "John",
age: 30,
}
Теперь добавим нашему объекту метод sayHi
, который будет выводить имя пользователя. Для этого методу потребуется доступ к информации, содержащейся в объекте, и вот тут нам и пригодится слово this
.
let user = {
name: "John",
age: 30,
sayHi() {
}
};
Впишите внутри фигурных скобок метода sayHi
следующее:
alert(this.name);
Посмотрите, что вернет код:
sayHi {
}
Итак, вот что у нас получилось:
let user = {
name: "John",
age: 30,
sayHi() {
alert(this.name);
}
};
А теперь вызовите метод sayHi
из объекта user
. Для этого допишите последнюю строчку кода — user.sayHi();
— и посмотрите на результат.
Метод sayHi
вызывается объектом user
, поэтому в данном примере значением this
является user
.
Конечно, мы можем получить имя пользователя и без помощи this
— просто обратившись к объекту через внешнюю переменную, в которой хранится ссылка на этот объект. Между фигурными скобками метода sayHi
впишите alert(user.name);
, т.е. замените в коде this
на user
. Что вернёт код?
let user = {
name: "John",
age: 30,
sayHi() {
// "user" вместо "this"
}
};
Метод sayHi
в данном случае тоже вернет John. Зачем же тогда писать лишние строчки кода и использовать this
?
Дело в том, что обращаясь к данным объекта напрямую через переменную, мы ставим работу нашего кода в зависимость от этой переменной. Если мы сохраним ссылку на объект в другую переменную, например, admin = user
, и перезапишем саму переменную user
, код будет работать неправильно. Метод sayHi
выдаст ошибку при работе с объектом admin
.
let user = {
name: "John",
age: 30,
sayHi() {
alert( user.name ); // приведёт к ошибке
}
};
let admin = user;
user = null; // перезапишем переменную для наглядности, теперь она не хранит ссылку на объект.
admin.sayHi(); // TypeError: Cannot read property 'name' of null
Чтобы методы всегда работали с данным объектом, тем самым, который их вызывает, мы и используем ключевое слово this
.
this не является фиксированным
В JavaScript ключевое слово this
ведёт себя иначе, чем в большинстве других языков программирования. Его можно использовать в любой функции, даже если это не метод объекта.
В следующем примере нет синтаксической ошибки:
function sayHi() {
alert( this.name );
}
Значение this
вычисляется во время выполнения кода, в зависимости от контекста.
Например, здесь одна и та же функция назначена двум разным объектам и имеет различное значение this
в вызовах:
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// используем одну и ту же функцию в двух объектах
user.f = sayHi;
admin.f = sayHi;
// эти вызовы имеют разное значение this
// "this" внутри функции - это объект "перед точкой"
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (нет разницы между использованием точки или квадратных скобок для доступа к объекту)
Правило простое: если вызывается obj.f()
, то во время вызова f
, this
– это obj
. Так что, в приведённом выше примере это либо user
, либо admin
.
У стрелочных функций нет this
Стрелочные функции особенные: у них нет своего «собственного» this
. Если мы ссылаемся на this
внутри такой функции, то оно берётся из внешней «нормальной» функции.
Например, здесь arrow()
использует значение this
из внешнего метода user.sayHi()
:
let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya
Это особенность стрелочных функций. Она полезна, когда мы на самом деле не хотим иметь отдельное this
, а скорее хотим взять его из внешнего контекста.
Подведем итог
- Методы могут ссылаться на объект через
this
. - Значение
this
определяется во время исполнения кода. - При объявлении любой функции в ней можно использовать
this
, но этотthis
не имеет значения до тех пор, пока функция не будет вызвана. - Функция может быть скопирована между объектами (из одного объекта в другой).
- Когда функция вызывается синтаксисом «метода» –
object.method()
, значениемthis
во время вызова являетсяobject
. - Cтрелочные функции являются особенными — у них нет
this
. Когда внутри стрелочной функции обращаются кthis
, то его значение берется извне.