Ключевое слово this

Последнее обновление: 15.07.2021

Поведение ключевого слова this зависит от контекста, в котором оно используется, и от того, в каком режиме оно используется - строгом или нестрогом.

Глобальный контекст

В глобальном контексте this ссылается на глобальный объект. В данном случае поведение не зависит от режима (строгий или нестрогий):

this.alert("global alert");
this.console.log("global console");

var currentDocument = this.document;

Но в данном случае использвание this избыточно.

Контекст функции

В пределах функции this ссылается на внешний контекст. Для функций, определенных в глобальном контексте, - это объект Window, который представляет окно браузера. Например:

function foo(){
	var bar = "bar2";
	console.log(this.bar);
}

var bar = "bar1";

foo();	// bar1

Если бы мы не использовали бы this, то обращение шло бы к локальной переменной, определенной внутри функции.

function foo(){
	var bar = "bar2";
	console.log(bar);
}

var bar = "bar1";

foo();	// bar2

Но если бы мы использовали строгий режим (strict mode), то this в этом случае имело бы значение undefined:

"use strict";
var obj = {
function foo(){
	var bar = "bar2";
	console.log(this.bar);
}
}

var bar = "bar1";

foo();	// ошибка - this - undefined

Контекст объекта

В контексте объекта, в том числе в его методах, ключевое слово this ссылается на этот же объект:

var o = {
	bar: "bar3",
	foo: function(){
		console.log(this.bar);
	}
}
var bar = "bar1";
o.foo();	// bar3

Примеры

Рассмотрим более сложный пример:

function foo(){
	var bar = "bar2";
	console.log(this.bar);
}

var o3 = {bar:"bar3", foo: foo};
var o4 = {bar:"bar4", foo: foo};

var bar = "bar1";

foo();	// bar1
o3.foo();	// bar3
o4.foo();	// bar4

Здесь определена глобальная переменная bar. И также в функции foo определена локальная переменная bar. Значение какой переменной будет выводиться в функции foo? Функция foo выводит значение глобальной переменной, так как данный скрипт запускается в нестрогом режиме, а значит ключеое слово this в функции foo ссылается на внешний контекст.

Иначе дело обстоит с объектами. Они определяют свой собственный контекст, в котором существует свое свойство bar. И при вызове метода foo внешним контекстом по отношению к функции будет контекст объектов o3 и o4.

Подобное поведение может привести к некоторому непонимаю в отдельных случаях. Так, рассмотрим другую ситуацию:

var o1 = {
	bar: "bar1",
	foo: function(){
		console.log(this.bar);
	}
}
var o2 = {bar: "bar2", foo: o1.foo};

var bar = "bar3";
var foo = o1.foo;

o1.foo();	// bar1
o2.foo();	// bar2
foo();		// bar3

Несмотря на то, что объект o2 использует метод foo из объекта o1, тем не менее функция o1.foo также будет искать значение для this.bar во внешнем котексте, то есть в контексте объекта o2. А в объекте o2 это значение равно bar: "bar2".

То же самое с глобальной переменной foo, которая ссылается на ту же функцию, что и метод o1.foo. В этом случае также будет происходить поиск значения для this.bar во внешним контексте, то есть в глобальном контексте, где определена переменная var bar = "bar3".

Однако если мы вызываем функцию из другой функции, вызываемая функция также будет использовать внешний контекст:

var bar = "bar2";

function daz(){
	var bar = "bar5";
	function maz(){
		
		console.log(this.bar);
	}
	maz();
}
daz();	// bar2

Здесь функция daz в качестве this.bar использует значение переменной bar из внешнего контекста, то есть значение глобальной переменной bar. Функция maz также в качестве this.bar использует значение переменной bar из внешнего контекста, а это значение this.bar из внешней функции daz, которое в свою очередь представляет значение глобальной переменной bar. Поэтому в итоге консоль выведет "bar2", а не "bar5".

Явная привязка

С помощью методов call() и apply() можно задать явную привязку функции к определенному контексту:

function foo(){
	console.log(this.bar);
}

var o3 = {bar: "bar3"}
var bar = "bar1";
foo();	// bar1
foo.apply(o3);	// bar3
// или
// foo.call(o3);

Во втором случае функция foo привязывается к объекту o3, который и определяет ее контекст. Поэтому во втором случае консоль выведет "bar3".

Метод bind

Метод f.bind(o) позволяет создать новую функцию с тем же телом и областью видимости, что и функция f, но с привязкой к объекту o:

function foo(){
	console.log(this.bar);
}

var o3 = {bar: "bar3"}
var bar = "bar1";
foo();	// bar1
var func = foo.bind(o3);
func();	// bar3

this и стрелочные функции

В стрелочных функциях объект, передаваемый через this, берется из родительского контекста, в котором определена стрелочная функция. Рассмотрим следующий пример:

const person = {
	name: "Tom",
	say:()=> console.log(`Меня зовут ${this.name}`)
}
person.say();	// Меня зовут 

Здесь стрелочная функция say() обращается к некому свойству this.name, но что здесь представляет this? Для внешнего контекста, в котором определена стрелочная функция - то есть для контекста объекта person this представляет глобальный объект (объект окна браузера). Однако глобальной переменной name не определено, поэтому на консоль будет выведено:

Меня зовут

Теперь немного изменим пример:

const person = {
	name: "Tom",
	hello(){
		console.log("Привет");
		let say = ()=> console.log(`Меня зовут ${this.name}`);
		say();
	}
}
person.hello();

Теперь стрелочная функция определена в методе hello(). this для этого метода представляет текущий объект person, где определен данный метод. Поэтому и в стрелочной функции this будет представлять объект person, а this.name - свойство name этого объекта. Поэтому при выполнении программы мы получим:

Привет
Меня зовут Tom

Несмотря на то что, стрелочные функции могут добавить забот при работе this, в то же время они могут решить ряд проблем. Так, при работе с несколькими контекстами мы вынуждены учитывать, в каком контексте определяется переменная. Например, возьмем следующий код:

const school ={
	title: "Oxford",
	courses: ["JavaScript", "TypeScript", "Java", "Go"],
	printCourses: function(){
		this.courses.forEach(function(course){
			console.log(this.title, course);
		})
	}
}
school.printCourses();

Функция printCourses проходит по всем курсам из массива и при их выводе предваряет их значением свойства title. Однако на консоли при запуске программы мы увидим следующее:

undefined "JavaScript"
undefined "TypeScript"
undefined "Java"
undefined "Go"

Мы видим, что значение this.title не определено, так как this как контекст объекта замещается глобальным контекстом. В этом случае нам надо передать подобное значение this.title или весь контекст объекта.

const school ={
	title: "Oxford",
	courses: ["JavaScript", "TypeScript", "Java", "Go"],
	printCourses: function(){
		const that = this;
		this.courses.forEach(function(course){
			console.log(that.title, course);
		})
	}
}
school.printCourses();

Стрелочные функции также позволяют решить данную проблему:

const school ={
	title: "Oxford",
	courses: ["JavaScript", "TypeScript", "Java", "Go"],
	printCourses: function(){
		this.courses.forEach((course)=>console.log(this.title, course))
	}
}
school.printCourses();

Контекстом для стрелочной функции в данном случае будет выступать контекст объекта school. Соответственно, нам недо определять дополнительные переменые для передачи данных в функцию.

Помощь сайту
WebMoney
  • P378451176208
  • Z280152397659
ЮMoney/Яндекс-Деньги
  • 410011174743222
PayPal
  • metanit22@mail.ru
Перевод на карту
  • Номер карты: 4048415020898850