Значение this это объект, в контексте которого выполняется Функции. Это одно из самых основных и, на первый взгляд, непонятных моментов в javascript.
Понимание того, 'что такое this на самом деле' открывает много интересных возможностей (таких как ООП, наследование), а также позволяет писать более качественный код.
this - это самый обычный объект. Все что нужно уметь - это понимать какой именно объект. Рассмотрим несколько простых примеров:
Создадим объект с одним методом, и одним свойством:
var obj = {
getWidth: function() {
return this.width;
},
width: 5,
}
console.log(obj.getWidth()); //5
Метод obj.getWidth() вернул значение obj.width. То есть можно предположить, что this указывает на родительский объект.
Многие думают, что это так и есть. Но это не так.
Запомните: this определяется только во время вызова функции. При создании Функции он неизвестен.
Но как тогда узнать на какой объект указывает this? На самом деле очень просто: this - это объект перед последней точкой:
obj.getWidth(); //this = obj
round.move(); //this = round
obj1.obj2.obj3.update(); //this = obj3
А если при вызове функции не было точки, то this будет равным window (в обычном режиме), либо undefined (в строгом режиме - при указании в начале кода 'use strict'):
//В обычном режиме
getWidth(); //this = window
move(); //this = window
//В строгом режиме
'use strict'
getWidth(); //this = undefined
move(); //this = undefined
Это все основные моменты, касающиеся this. Чтобы окончательно разобраться, рассмотрим несколько примеров (все примеры буду рассматриваться в строгом (современном) режиме):
Примеры
Пример
Напишем объект user, с свойством name, и методом sayHi():
var user = {
name: 'Андрей',
sayHi: function() {
document.write('Привет. Меня зовут ' + this.name);
}
}
user.sayHi();
Результат выполнения кода:
Пример
Тепер скопируем метод sayHi() в другой объект:
var user = {
name: 'Андрей',
sayHi: function() {
document.write('Привет. Меня зовут ' + this.name);
}
}
var user2 = {
name: 'Вася',
}
user2.sayHi = user.sayHi;
user2.sayHi();
Благодаря тому, что метод был вызван как user2.sayHi() - this равен user2. А в user2 свойство name равно 'Вася'.
Результат выполнения кода:
Пример
Также метод можно скопировать не только в объект, а и в переменную:
var user = {
name: 'Андрей',
sayHi: function() {
document.write('Привет. Меня зовут ' + this.name);
}
}
var sayHi = user.sayHi;
sayHi();
Но чему в этом случае будет равен this? Посмотрим как метод был вызван:
sayHi();
То есть нет никаких точек. Следовательно this равно undefined (либо window в обычном режиме). А это значит что в строгом режиме этот код вызовет ошибку. Так как 'this.name' будет равносильно 'undefined.name' (а в обычном режиме: window.name);
Пример
В этом примере посмотрим на ошибку, которую допускают очень часто. Выполним метод seyHi(). Но не сразу, а через 2 секунды:
var user = {
name: 'Андрей',
sayHi: function() {
document.write('Привет. Меня зовут ' + this.name);
}
}
setTimeout(user.sayHi, 2000);
В чем здесь ошибка? Посмотрим, как может работать функция setTimeout:
function setTimeout(func, time) {
//Какой-то код
func();
//Какой-то код
}
То есть снова нет никаких точек. Ситуация такая же что и в предыдущем примере.
Пример
Посмотрим как можно обойти эту ошибку:
var user = {
name: 'Андрей',
sayHi: function() {
alert('Привет. Меня зовут ' + this.name);
}
}
setTimeout(function() {
user.sayHi();
}, 2000);
То есть мы оборачиваем вызов метода в еще одну функцию, благодаря чему метод вызывается как user.sayHi() и this сохраняется.
Результат выполнения кода:
Пример
Рассмотрим еще одну частую ошибку. Перенесем таймер внутрь метода:
var user = {
name: 'Андрей',
sayHi: function() {
setTimeout(function() {
document.write('Привет. Меня зовут ' + this.name);
}, 2000);
}
}
user.sayHi();
Чему в этом примере будет равно this? this есть у всех функций. А в данном примере this находится не в методе, а в Функции, что передается таймеру:
function()
{
document.write('Привет. Меня зовут ' + this.name);
}
Как мы уже выяснили выше, фукцнция, что передается в таймер, выполняется как func(). Следовательно в этой Функции this = undefined. То есть мы потеряли контекст.
Пример
Посмотрим как обойти это ошибку:
var user = {
name: 'Андрей',
sayHi: function() {
var self = this;
setTimeout(function() {
document.write('Привет. Меня зовут ' + self.name);
}, 2000);
}
}
user.sayHi();
Здесь мы создали переменную self, которая указывает на this объекта obj. И контекст больше не теряется.
Также эту ошибку можно было обойти методом bind