Ключевое слово 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, то его значение берется извне.