Введение

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

Основные преимущества this заключаются в том, что он позволяет переиспользовать функции.

 
function foo (num) {
	console.log("foo" + num)
	this.count++
}
 
foo.count = 0
var i
 
for (i = 0; i < 10; i++) {
	if (i > 5) {
		foo(i)
	}
} 
 
// foo: 6
// foo: 7
// foo: 8
// foo: 9
 

Функция foo() была вызвана 0 раз!!!

Это так, потому что this.count указывает не на объект , а на созданную глобальную переменную.

this не связана с областью видимости так, как мы это понимаем.

Что такое this ?

При вызове функции активируется “запись активации”, также называемая контекстом выполнения.

Запись содержит информацию откуда была вызвана функция (стек вызовов) , как она вызвана, какие параметры были переданы и так далее.

Одни из свойств этой записи при передачи является ссылка this .

Первое правило: use strict

#useStrict Если действует режим strict : глобальный объект на момент исполнения используется для связывания по умолчанию, поэтому, вместо этого присваивается undefined.

 
function foo () {
	"use strict"
	console.log(this.a)
}
 
var a = 2;
foo() // TypeError this is undefined
 

Но, при этом

 
function foo () {
	console.log(this.a)
	var a = 2
}
 
...
 
(function) () {
	"use strict"
	foo() //2
} ()
 

Второе правило: Неявное связывание

  1. Наличие у места вызова контекстного объекта - владельца.
 
function foo() {
	console.log(this.a)
}
 
var obj ={
	a: 2,
	foo: foo // вызывает функцию foo
}
 
obj.foo() //2
  1. Для теста вызова важен только верхний и последний уровень
 
function foo() {
	console.log(this.a)
}
 
var obj2 = {
	a: 42,
	foo: foo // вызывает функцию foo()
}
 
var obj1 = {
	a: 2,
	obj2: obj2 // вызывает var obj2
}
 
obj1.obj2.foo //42
  1. Неявная потеря this

ключевое: теряется связывание, возвращается связывание по умолчанию - глобального объекта или undefined.

 
function foo() {
	console.log(this.a)
}
 
var obj = {
	a: 2,
	foo: foo
}
 
var bar = obj.foo
var a = "oops, Global!" // глобальное свойство
bar() // oops, Global!
  1. Потеря связывания this обратными вызовами.

Третье правило: Явное связывание

  1. Явное связывание Существуют методы#call и#apply

В первом параметре метода содержится объект, который используется для this Мы напрямую указываем какое значение должно использоваться для this

 
function foo() {
	console.log(this.a)
}
 
var obj = {
	a: 2
}
 
foo.call(obj) //2
 
  1. Жёсткое связывание
 
function foo() {
	console.log(this.a)
}
 
var obj = {
	a: 2
}
 
var bar = function() {
	foo.call(obj)
}
 
bar() //2
setTimeOut(bar, 1000) //2
bar.call(window) //2
  1. Контексты вызовов API

Функции многих библиотек , а также многие … поддерживают context, который избавляет нас от необходимости использовать#bind, чтобы функция гарантировала использование this.

function foo(el) {
	console.log(el, this.id)
} 
 
var obj = {
	id: "awesome"
}
 
[1,2,3].forEach(foo, obj)

Четвёртое правило: Связывание с new

Когда функция вызывается после оператора new (такие вызовы называются вызовами-конструкторами), они автоматически выполняют следующие действия:

  1. Конструируются как новый объект
  2. Производят его связывание с [[Prototype]]
  3. Сконструированный объект назначается в качестве связывания this для этого вызова функции
  4. Если функция не возвращает свой альтернативный объект, то вызов функции автоматически возвращает сконструированный объект.
 
function foo(a) {
	this.a = a;
}
 
var bar = new foo(2) 
console.log(bar.a) //2
 

Определение this

  • Функция вызова с new
  • Функция вызвана с call и apply
  • Функция вызвана с контекстом
  • this по умолчанию при use strict либо undefined или global

Исключения:

Если передать в this (call, bind и apply) значение null или undefined , то значения фактически игнорируются.

 
function foo() {
	console.log(this.a)
}
 
var a = 2;
foo.call(null) //2
 

Лексическое поведение this

Лексическая область видимости стрелочной функции:

 
function foo() {
	return (a) => {
	//`this` здесь лексически наследуется от foo()
	console.log(this.a)
	}
}
 
var obj1 = {
	a: 2
}
 
var obj2 = {
	a: 3
}
 
var bar = foo.call(obj1)
bar.call(obj2) // 2, а не 3!
 

Лексическое связывание стрелочной функции не может быть переопределено даже с new. Распространённое использование - это колбеки.

call, bind, apply

Объекты существуют в двух форматах:

  • литеральной
 
var myObj = {
	key: value
}
  • конструированной
 
var myObj = new Object()
 
myObj.key = value
 
var myObj = {
	a: 4,
	writable: true,
	configurable: false,
	enumerable: true
}