Значение 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

См. также bind, apply, call.