Введение
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
} ()
Второе правило: Неявное связывание
- Наличие у места вызова контекстного объекта - владельца.
function foo() {
console.log(this.a)
}
var obj ={
a: 2,
foo: foo // вызывает функцию foo
}
obj.foo() //2
- Для теста вызова важен только верхний и последний уровень
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
- Неявная потеря
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!
- Потеря связывания
this
обратными вызовами.
Третье правило: Явное связывание
В первом параметре метода содержится объект, который используется для this
Мы напрямую указываем какое значение должно использоваться для this
function foo() {
console.log(this.a)
}
var obj = {
a: 2
}
foo.call(obj) //2
- Жёсткое связывание
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
- Контексты вызовов API
Функции многих библиотек , а также многие … поддерживают context, который избавляет нас от необходимости использовать#bind, чтобы функция гарантировала использование this
.
function foo(el) {
console.log(el, this.id)
}
var obj = {
id: "awesome"
}
[1,2,3].forEach(foo, obj)
Четвёртое правило: Связывание с new
Когда функция вызывается после оператора new (такие вызовы называются вызовами-конструкторами), они автоматически выполняют следующие действия:
- Конструируются как новый объект
- Производят его связывание с
[[Prototype]]
- Сконструированный объект назначается в качестве связывания
this
для этого вызова функции - Если функция не возвращает свой альтернативный объект, то вызов функции автоматически возвращает сконструированный объект.
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
}