#4 This в Javascript

poster
В этом уроке мы разберемся в том, что такое this, как его применять в функциях, прототипах и обьектах. Разберем проблемы, которые могут возникать при использовании this.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

Всем привет. Сегодня мы с вами поговорим о том, что такое this и зачем он нужен в javascript. Вообще this - это переменная, которая ссылается на текущий обьект. Еще очень часто говорят "на текущий контекст". Возможно эта фраза вам ничего не обьяснила, но сейчас вы все поймете.

Если мы напишем

console.log(this)

и посмотрим в браузер, то мы увидим, что у нас вывелся обьект window. Это как раз и означает, что this ссылается на текущий обьект. И текущий обьект у нас - window.

Если мы в обьекте window создадим переменную, например

window.hello = 'hello';
console.log(this.hello);

то тогда this.hello выведет на экран "hello". То есть this действительно ссылается на обьект window, а window содержит в себе переменную hello.

Теперь давайте создадим функцию helloWorld и выведем в ней this.

var helloWorld = function () {
  console.log(this);
}

Если же мы вызовем сейчас эту функцию, то увидим, что она так же будет ссылаться на window. Почему? Потому что helloWorld вызвана в контексте window, а значит она будет ссылаться на window.

Давайте посмотрим когда же у нас this изменяется. Например

var human = {
  name: 'Alexa',
  getName: function () {
    console.log(this);
  }
};

У нас есть обьект с полем name и функцией getName, которая будет нам в консоль выводить this.

Теперь давайте вызовем

human.getName();

Если мы посмотрим в браузер, то увидим, что у нас контекст вызова уже не window, а наш обьект human. И у него есть функция getName и проперти name. Почему это так работает? Посколько this вызвана сейчас в контексте обьекта human, то оно и ссылается на human.

Давайте попробем пример с прототипным наследованием. Создадим класс Mail

var Mail = function () {
  this.letter = 'This is my letter';
  console.log(this);
}

И создадим экземпляр класса Mail.

var mail = new Mail();

Если мы посмотрим в браузер, то у нас контекст this ссылается на наш mail. Причем именно на экземпляр класса Mail. Потому что, если мы создадим здесь какой-то другой mail, то есть еще один экземпляр класса, то он уже будет ссылаться на свой обьект, которому будет присвоено свойство letter.

var mail2 = new Mail();

Чаще всего this используется именно в прототипном наследовании, поскольку очень удобно записывать все значения и методы в this, а потом их использовать.

Если мы опишем метод getLetter и вызовем его

Mail.prototype.getLetter = function () {
  console.log(this);
}
mail.getLetter();

то мы увидим, что this все так же ссылается на наш экземпляр класса.

Также у меня в html подключен script jquery и есть button. и ниже уже идет мой javascript.

Давайте теперь попробуем сделать пример с jquery. Допустим мы хотим найти на странице button и навесить на него click. И мы хотим, чтобы по клику вызывалась функция getName.

$('button').click(human.getName);

Когда мы кликаем на button, то мы видим, что в консоли выводится не наш обьект human, а button. Почему это выходит? Потому что функция human.getName вызывается в контексте click, а значит в контексте обьекта jquery. Именно поэтому у нас здесь неправильный контекст и если мы попробуем вывести this.name, то у нас был бы undefined. И у нас бы приложение не работало.

Как нам сделать, чтобы this был правильный и ссылался на human? Для этого мы можем использовать встроенную javascript функцию bind.

$('button').click(human.getName.bind(human));

Если мы сейчас кликаем, то видим, что у нас выводится getName Alexa.

Что такое .bind? Это такая вещь, которая позволяет изменить контекст вызова функции. Если раньше у нас контекст был неправильный, то мы можем передать первым аргументом контекст который мы хотим, в данном случае это обьект human, и теперь у нас this, когда мы будем вызывать getName, будет ссылаться на human.

Всегда нужно помнить, что у функции будет контекст обьекта, из которого она была вызвана.

И давайте рассмотрим немного более часто используемую вещь - это смена контекста. Допустим у нас есть обьект sport.

var sport = {
  tournament: 'The Master',
  players: [
    {
      name: 'Wood',
      age: 37
    },
    {
      name: 'Mike',
      age: 43
    }
  ]
};

И теперь мы хотим создать функцию, которая будет выводить нам всех игроком.

show: function () {
  this.players.forEach(function (person) {
    console.log(person, this);
  });
}

Мы используем this.players, чтобы обратиться к всем игрокам и функцию forEach, которая позволяет проходить по каждому елементу массива. Первым аргументом функции внутри forEach будет person, каждый елемент массива.

Вызовем

sport.show();

Мы видим, что console.log в forEach вывел person, а this у нас неправильный и ссылается на window. Если мы выведем this в начале функции, то он будет правильный.

show: function () {
  console.log(this);
}

Как же изменить контекст на правильный? Давайте создадим локальную переменную до того, как мы зашли в forEach.

show: function () {
  var self = this;
  this.players.forEach(function (person) {
    console.log(person, this);
  });
}

Так как это локальная переменная, то она будет доступна нам внутри forEach. Если мы выведем self, то увидим, что у нас правильный контекст. Значит мы можем написать какую-то информацию.

show: function () {
  var self = this;
  this.players.forEach(function (person) {
    console.log(person.name + ' is playing' + self.tournament);
  });
}

Это очень часто используемый подход, когда у нас меняется контекст, а нам нужно сохранить его на предыдущий.

Вообще тема this достаточно обширная и сложная и мы рассмотрели с вами только самые используемые кейсы.

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
Артур Владимирович
9 лет назад
Как всегда спасибо за урок! И по старинке указание на опечатку=) На этот раз letterr. Может проще взять меня модератором сайта?)))
monsterlessons
9 лет назад
Как всегда, на здоровье)) У меня не предусмотрено абсолютно никакого функционала для модерации, к сожалению. Так что можете писать об ошибках, либо в комментариях, либо на почту monsterlessons@gmail.com.