Знание значения и практическое применение ключевого слова ‘this’ в JavaScript.
Ключевое слово this
в JavaScript — это невероятно мощная концепция. Чаще всего оно вызывает недоумение у новичков или разработчиков, которые не понимают, как его использовать, а также способствует появлению нежелательных ошибок в нашем коде. В этой статье мы рассмотрим, что означает ключевое слово this
, а также три (3) магических метода, которые необходимы для его применения.
Необходимые условия
-
Базовое понимание HTML и CSS.
-
Базовое понимание JavaScript и того, как он работает за кулисами.
Что такое ключевое слово ‘this’?
Ключевое слово this
— это специальная переменная, созданная для контекста выполнения каждой функции.
За кулисами JavaScript каждая функция получает контекст выполнения во время исполнения. Каждый контекст выполнения включает в себя переменную окружения, цепочку областей видимости и ключевое слово this
.
Вы можете считать ключевое слово this
местоимением в английском языке. Рассмотрим пример: «Меня зовут Аахил, я люблю писать». «I» в предложении относится к «Aahil». Именно это и делает ключевое слово this
, оно обращается к вызывающей его функции.
Значение созданного ключевого слова this
, указывает на владельца функции, в которой оно используется. Другими словами, когда функция выполняется, она получает свое собственное отдельное ключевое слово this
, значением которого является функция, в которой используется ключевое слово this
.
В отличие от других переменных, ключевое слово this
не является СТАТИЧЕСКОЙ переменной. Оно получает свое значение в зависимости от того, КАК вызывается функция. Ниже приведены 3 способа вызова функций в JavaScript 👇:
(1) Как метод 👇:
Функция, объявленная в объекте, является методом. Значение ключевого слова this
при использовании в методе указывает на объект, на котором вызывается метод.
Рассмотрим пример кода.
const sample1 = {
name: "Aahil",
dateOfBirth: 1996,
calcAge() {
console.log(`${this.name} is ${2022 - this.dateOfBirth} years old`);
},
};
sample1.calcAge();
Давайте разберем пример кода. Выше произошли следующие действия;
-
Был создан объект-литерал
sample1
. Он содержит 2 свойства,name
иdateOfBirth
, и методcalcAge()
. -
Метод
calcAge()
выводит на консоль браузера строку, состоящую из свойства name и вычисленной даты рождения. -
Объект sample1 вызывает метод
calcAge()
.
Выход 👇:
Значением ключевого слова this
выше является объект, вызывающий метод calcAge()
, которым является sample1
. Следовательно, this.name
совпадает с sample1.name
, который является строкой ‘Aahil’.
Мы можем продолжить и подтвердить значение ключевого слова this
. Смотрите пример ниже 👇
const sample1 = {
calcAge() {
console.log(this);
},
};
sample1.calcAge();
Выход 👇:
Как мы видим выше, ключевое слово this
указывает на объект sample1
.
(2) Как обычный вызов функции 👇:
Когда мы создаем функцию, ожидается, что она должна быть вызвана перед запуском. Значение ключевого слова this
при использовании в функции возвращается как undefined
при вызове этой функции. Это справедливо только для выражений функций и объявлений функций, но не для стрелочных функций.
ПРИМЕЧАНИЕ👉: Это применимо только в строгом режиме, в противном случае ключевое слово this
указывает на глобальный объект окна.
Давайте посмотрим на это в действии.
"use strict";
const sample2 = function () {
console.log(this);
};
sample2();
В приведенном выше фрагменте кода мы явно задали выполнение скрипта в строгом режиме. У нас также есть простое функциональное выражение sample2()
, которое выводит ключевое слово this
на консоль браузера.
Вывод👇:
Как было сказано ранее, значение this
здесь возвращается как undefined
в строгом режиме. Теперь посмотрим на эффект от выполнения того же кода в небрежном режиме.
const sample2 = function () {
console.log(this);
};
sample2();
Выход👇:
Выводом является объект глобального окна — это объект, доступный в глобальной области видимости.
ПРИМЕЧАНИЕ👉:
Использование строгого режима очень важно, так как он предотвращает молчаливый отказ JavaScript, и мы устанавливаем строгий режим, добавляя строку » use strict » в начало файла скрипта.
Мы не можем говорить об использовании this
в выражениях функций и объявлениях функций, не упомянув о его эффекте при использовании в СТРЕЛОЧНОЙ ФУНКЦИИ.
В качестве стрелочной функции 👇:
Стрелочная функция — это упрощенная альтернатива для создания функций в JavaScript. Стрелочные функции не получают собственной переменной this
, однако она использует ключевое слово this
своей родительской области видимости, которое называется лексическим ключевым словом this
.
Рассмотрим пример кода.
const sample3a = () => console.log(this);
sample3a()
В приведенном выше примере функция arrow регистрирует ключевое слово this
в консоли браузера.
Вывод👇:
Результат выполнения приведенного выше кода возвращает объект глобального окна. Помните, что значением ключевого слова this
при вызове функции в небрежном режиме является объект глобального окна. Это означает, что функция arrow не имеет собственного ключевого слова this
, но указывает на ключевое слово this
внешней области видимости (родительской области видимости).
Мы можем наблюдать переменную this
внешней области видимости, просто записывая this
в консоль браузера, не находясь внутри какого-либо блока кода (или функции).
console.log(this)
Вывод👇:
Переменная this
внешней области видимости является объектом глобального окна, поэтому переменная this
функции стрелки выше указывает на объект глобального окна. На рисунке ниже приведено краткое описание этого.
Мы можем видеть значение ключевого слова this
, когда функция arrow помещается в другой блок кода, в данном случае в другую функцию.
const sample3b = function () {
const sample3bArrowFunction = () => {
console.log(this);
};
sample3bArrowFunction()
};
sample3b();
Давайте разберем фрагмент кода;
-
Функция
sample3b()
, которая содержит стрелочную функциюsample3bArrowFunction()
. -
sample3bArrowFunction()
просто записывает в консоль переменнуюthis
.
Output👇:
Результатом этого примера является undefined
. Это происходит потому, что sample3bArrowFunction()
не получает свою собственную переменную this
, а использует ключевое слово this
внешней области видимости, которой в данном случае является функциональное выражение sample3b()
.
Помните из нашего предыстории, мы установили, что функциональные выражения возвращают значение this
как undefined
. Поэтому ключевое слово this
в sample3bArrowFunction()
также будет undefined
.
ПРИМЕЧАНИЕ👉: Стрелочная функция не является способом вызова функции, но это важный и особый случай, который мы должны учитывать при изучении этого
.
(3) Как слушатели событий 👇:
При использовании слушателей событий в JavaScript мы выбираем элемент, который хотим прослушать, затем вызываем метод addEventListener()
с двумя параметрами. Первый параметр — это событие, которое мы прослушиваем, а второй — функция, которая будет запущена при наступлении этого события.
Ключевое слово this
внутри функции, которая вызывается при наступлении события, указывает на элемент, вызывающий это событие. Это связано с тем, что в объектной модели документа (DOM) все элементы являются объектами, поэтому кажется, что объект вызывает функцию, как и обычный метод.
Давайте обсудим это на примере.
const buttonEl = document.querySelector('.btn')
const handleClick = function(){
console.log(this);
}
buttonEl.addEventListener('click', handleClick);
В приведенном выше фрагменте кода выполняются следующие действия;
(1) Переменная buttonEl
содержит HTML-элемент кнопки.
(2) Функция handleClick()
просто регистрирует ключевое слово this
в консоли браузера.
(3) К buttonEL
прикреплен слушатель событий с 2 параметрами. К ним относятся;
-
Событие
click
, которое прослушивается при нажатии на кнопку. -
Функция обратного вызова
handleClick()
, которая вызывается только при нажатии на кнопку.
Вывод👇:
Ключевое слово this
указывает на элемент, вызывающий событие, и в данном случае элементом, вызывающим событие, является элемент button
. Вот почему результатом нашего фрагмента кода является элемент button
.
ПРИМЕЧАНИЕ 👉:
Значение ключевого слова this
присваивается только при вызове функции.
Мы выяснили, что ключевое слово this
не является СТАТИЧЕСКИМ, то есть оно изменяется в зависимости от того, как вызывается функция. Однако есть способы вручную установить ключевое слово this
. Как это здорово, давайте разберемся.
Следующие три (3) магических ✨ метода используются для ручной установки ключевого слова this
;
(1) Метод Call() 👇.
Метод Call()
позволяет функции/методу, определенному в объекте, быть использованным другим объектом без переписывания этого метода. Используя метод call()
, вы можете написать функцию один раз, а затем использовать ее на нескольких объектах.
Мы используем метод call()
, когда вызываем функцию. Метод call()
принимает список аргументов, где первый аргумент — объект, это будет значение ключевого слова this
, а остальные — аргументы, относящиеся к функции.
Рассмотрим практический пример.
function sample5() {
console.log(`${this.name} is ${this.age} old`);
}
const sample5Obj = {
name: "prince",
age: 24,
};
sample5.call(sample5Obj);
Выше произошли следующие действия;
- Функция
sample5()
просто выводит на консоль имя и возраст. - Объект
sample5Obj
содержит два (2) свойства, имя и возраст.
Все это не представляет собой ничего нового, пока мы не вызовем функцию sample5()
с помощью метода call()
и не передадим в качестве аргумента объект sample5Obj
.
Давайте посмотрим результат этого примера.
Вывод👇:
Вывод выше берет переменные name и age из sample5Obj
. Это означает, что значение ключевого слова this
указывает на sample5Obj
. Это происходит потому, что мы использовали метод call()
для его явного задания.
Помните, что вызов функции без использования метода call()
вернул бы значение this
как undefined
. Используя метод call()
, мы можем назначить функцию sample5()
нескольким объектам, в чем мы можем убедиться ниже, добавив еще один объект.
function sample5() {
console.log(`${this.name} is ${this.age} years old`);
}
const sample5Obj1 = {
name: "Prince",
age: 24,
};
const sample5Obj2 = {
name: "Aahil",
age: 45,
};
sample5.call(sample5Obj1);
sample5.call(sample5Obj2);
Здесь мы добавили еще один объект sample5Obj2
, чтобы показать, что функция может использоваться в нескольких объектах, и ключевое слово this
будет меняться в зависимости от того, какой объект мы передаем в метод call()
.
Вывод👇:
Результат вызова функции sample5()
на обоих объектах меняется, потому что мы меняем первый аргумент метода call()
.
ПРИМЕЧАНИЕ👇:
Синтаксис для использования метода call()
следующий;
function.call(object, arg1, arg2,....,argn);
Где;
-
Первый аргумент определяет, каким будет ключевое слово
this
. -
Остальные аргументы
arg1
,arg2
, иargn
определяют аргументы функции.
(2) Метод apply()👇.
Метод apply()
делает то же самое, что и метод call()
, с той лишь разницей, что вы передаете аргументы функции в виде массива вместо того, чтобы передавать их напрямую.
Давайте рассмотрим пример кода.
function sample6(name, age) {
console.log(this);
console.log(
`${name} is ${age} years old and the name of this object is ${this.objectName}`
);
}
const sample6Obj = {
objectName: "object1",
};
const args = ["aahil", 14];
sample6.apply(sample6Obj, args);
Давайте разберем приведенные выше действия;
(1) Функция sample6()
с параметрами имя и возраст. sample6()
записывает в консоль браузера ключевое слово this
и строку шаблона.
(2) Объект sample6Obj
, который содержит свойство objectName
.
(3) Массив args
, содержащий 2 элемента.
(4) sample6()
вызывается с помощью apply()
. В качестве первого аргумента принимается sample6Obj
, означающий, что значением this
будет sample6Obj1
, а в качестве второго аргумента принимается массив args
.
Вывод👇:
Давайте теперь проанализируем наш вывод;
(1) Первый вывод, который мы имеем — это результат записи ключевого слова this
в консоль браузера. Выводом является объект sample6Obj
, который мы создали с помощью метода apply()
.
(2) Второй вывод — это строка шаблона, составленная из элементов массива args
. Использование метода apply позволяет нам передавать аргументы в массив и передавать массив в качестве аргумента при вызове функции.
ПРИМЕЧАНИЕ:👉 apply()
сейчас практически не используется, и тот же самый паттерн, который он использует, можно сделать с помощью метода call()
и оператора spread.
Давайте посмотрим на это ниже 👇.
sample6.call(sample6Obj, ...parameters);
Вывод этого кода даст тот же результат, что и ранее.
ПРИМЕЧАНИЕ:👇
Синтаксис для использования метода apply()
следующий;
function.apply(object, [args]);
Первый аргумент определяет, каким будет значение this
, а второй аргумент определяет массив аргументов, относящихся к функции.
(3) Метод bind() 👇.
Метод bind()
используется для явного задания ключевого слова this
, так же как и методы call()
и apply()
. Разница лишь в том, что вместо немедленного вызова функции он возвращает новую функцию с привязанным к ней ключевым словом this
.
Когда мы используем метод bind()
, мы можем получить совершенно новую функцию со значением this
, которое будет тем объектом, которому мы его зададим. Теперь эту функцию можно использовать в разных местах.
Пример👇:
function sample7(name, age) {
console.log(this);
console.log(
`${name} is ${age} years old and the name of this object is ${this.objectName}`
);
}
const sample7Obj = {
objectName: "object1",
};
const sample7Bind = sample7.bind(sample7Obj);
sample7Bind("aahil", 24);
У нас такой же синтаксис, как и раньше, единственное отличие — функция sample7Bind()
. Эта функция создается, когда метод bind()
используется в функции sample7()
для явной установки ее ключевого слова this
в объект sample7Obj
.
sample7Bind()
вызывается с аргументами функции, ключевое слово которой this
указывает на объект sample7Obj
.
Выход👇:
Вывод такой же, как и при использовании apply()
или call()
, единственная разница в том, что метод bind возвращает другую функцию, а методы apply()
и call()
просто вызывают функцию напрямую.
ПРИМЕЧАНИЕ 👉: ** Полезным применением использования bind()
является **частичное применение. Это когда некоторые аргументы функции передаются в метод bind по умолчанию, затем при вызове функции этот аргумент будет пропущен, поскольку теперь он служит параметром по умолчанию этой функции.
Заключение
Это очень объемная статья, но я надеюсь, что мы достигли поставленных целей и получили более глубокое понимание того, как ключевое слово this
динамически изменяется в зависимости от того, как вызываются функции, и как мы можем явно определить значение ключевого слова this
.
Важно отметить, что ключевое слово this
— это просто переменная, и если вы не уверены в значении ключевого слова this
, вы можете** просто войти в консоль браузера**, чтобы подстраховаться.
Спасибо, что прочитали 😊.