
Всем привет. Сегодня мы с вами поговорим о том, что такое 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 достаточно обширная и сложная и мы рассмотрели с вами только самые используемые кейсы.