Ключевое слово this. Основы
Ранее говорилось о том, что при создании Лексического Окружения, например если была вызвана функция, формируется соответствующая Запись Окружения. И эта Запись Окружения содержит в себе не только информацию о переменных текущей области видимости, но и ключевое слово this
, к которому можно обратиться напрямую из кода. Значение this
динамически устанавливается JavaScript-движком на этапе создания контекста выполнения и указывает на объект, связанный с этим контекстом.
Значение this
в глобальном контексте
Если говорить о глобальном контексте выполнения, который формируется при первом запуске программы, то в рамках этого контекста ключевое слово this
будет ссылаться на глобальный объект Window
. Например, если вы откроете в браузере Консоль Разработчика и введете this
, то ответом вам вернется объект Window
.
this
> Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
this.a = 37;
console.log(window.a);
> 37
Значение this
в контексте функции
Если говорить о this
в рамках контекста выполнения функции, то здесь важно понимать, что объект, на который будет ссылаться ключевое слово this
зависит от того, где и при каких условиях эта функция была вызвана. Например, что можно сказать о значении this
для этой функции:
function main() {
console.log(this);
}
Здесь функция просто определена и еще не была вызвана, поэтому о значении this
в рамках этой функции пока ничего нельзя сказать. Оно будет установлено во время вызова этой функции.
Простой вызов функции
В случае вызова этой функции не в строгом режиме, значением this
будет являться глобальный объект Window
.
function main() {
console.log(this);
}
main(); // вызов функции
> Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
А в строгом режиме use strict
, значением this
будет undefined
function main() {
"use strict";
console.log(this);
}
main(); // вызов функции
> undefined
Вызов функции как метода объекта
Если функция вызывается как метод объекта, то ключевое слово this
в рамках этой функции будет указывать на сам этот объект, методом которого она была вызвана.
let obj = {
property: 10,
method: function() {
console.log(this);
console.log(this.property);
}
};
obj.method();
// this будет ссылаться на сам объект из переменной obj
> {property: 10, method: ƒ}
> 10
Здесь снова стоит заметить, что значение this
не зависит от того, как и где функция была определена, а только от того, каким образом она была вызвана. Например, если определить функцию отдельно от объекта, а потом просто добавить её как метод в этот объект, то результат её вызова останется прежним.
let obj = {
property: 10
};
function func() {
console.log(this);
console.log(this.property);
}
obj.method = func; // добавили функцию в объект
obj.method();
// this всё так же будет ссылаться на сам объект из переменной obj, методом которого была вызвана функция
> {property: 10, method: ƒ}
> 10
Другими словами значением this
в данном случае является ближайший объект перед точкой. Может быть так, что объекты будут вложены друг в друга, например
function func() {
console.log(this);
console.log(this.property);
}
let obj = {
property: 10,
innerObj: {
property:5,
method: func
}
};
obj.innerObj.method();
> {property: 5, method: ƒ}
> 5
В данном случае this
ссылается на вложенный объект innerObj
, так как именно его методом была вызвана функция. По другому вызов можно записать так
function func() {
console.log(this);
console.log(this.property);
}
let obj = {
property: 10,
innerObj: {
property:5,
method: func
}
};
let target = obj.innerObj;
target.method();
> {property: 5, method: ƒ}
> 5
Поэтому тот факт, что innerObj
является свойством другого объекта не имеет значения, важно лишь то, что функция вызывается именно в отношении этого объекта.
Явная передача контекста в функцию
Так же есть возможность при вызове функции явно передать ей значение this
с помощью специальных выстроенных методов call
, apply
.
function add(c, d) {
return this.a + this.b + c + d;
}
var obj = { a: 1, b: 3 };
// Здесь происходит вызов функции add с использованием встроенного метода call
// Первым параметром передаётся объект, на который будет ссылаться ключевое слово this в рамках функции add
// Следующими параметрами передаются значения аргументов функции (c и d соответственно)
let result1 = add.call(obj, 5, 7); // 1 + 3 + 5 + 7
console.log(result1); // 16
// Здесь происходит вызов функции add с использованием встроенного метода apply
// Первым параметром передаётся объект, на который будет ссылаться ключевое слово this в рамках функции add
// Следующим параметром передаётся значения аргументов функции в виде массива ( [c, d] )
let result2 = add.apply(obj, [10, 20]); // 1 + 3 + 10 + 20
console.log(result2); // 34
Первым параметром в них задаётся значение this
, а последующими необязательными параметрами - аргументы, с которыми будет вызываться функция. Причем для метода call
аргументы передаются списком через запятую fun.call(thisArg[, arg1[, arg2[, ...]]])
. А для метода apply
они передаются при помощи одного массива fun.apply(thisArg[, argsArray])
.
Необходимо отметить,что если методам call
и apply
, передается значение с this
, которое не является при этом объектом, то будет предпринята попытка преобразовать это значение в объект. Если переданное значение является примитивным типом, таким как 7
или 'строка'
, оно будет преобразовано в свой объектный аналог с использованием родственного конструктора, так примитив 7
преобразовывается в объект через new Number(7)
, а строка 'строка'
в объект через new String('строка')
, и т.д.
function func() {
console.log(typeof this);
}
func.call(7); // примитив 7 будет преобразован в объектный аналог [object Number]
> object
Так же еще есть метод bind
, который тоже позволяет явно передать контекст в функцию, но в отличие от методов call
и apply
не вызывает сразу функцию, а возвращает её обёртку. Об это методе будет рассказано в следующих частях курса.
Другие варианты установки this
Помимо описанных случаев есть еще больше вариантов и определенных условий, когда значение this
устанавливается по другим правилам. Например, в рамках конструкторов, стрелочных функций, обработчиков событий DOM и др. Но эти темы будут описаны в следующих частях курса, поэтому и специфика изменения значения this
будет затрагиваться в соответствующих разделах.
Оставить комментарий