Ключевое слово 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 будет затрагиваться в соответствующих разделах.
Оставить комментарий