Давай начнём издалека, чтобы ты точно смог понять что такое this в JavaScript.
Ключевые зарезервированные слова в JavaScript
Во-первых, this — это зарезервированное ключевое слово в JavaScript. Это значит, что им нельзя называть переменные или функции. Когда «среда выполнения кода» доходит до слова this в твоём коде, тогда она точно знает, что это часть синтаксиса самого языка.
Если говорить простыми словами, то вы — «человек», ваш друг — «человек», ваш отец — «человек», ну и так далее. Слово «человек» всеми представителями людей воспринимается одинаково. Вы не встретите ни одного человека с именем «Человек». Точно так же и в JavaScript. Слово this всегда обозначает какую-то одну смысловую суть.
JavaScript — это объектно-ориентированный язык программирования
Во-вторых, ты должен знать, что в JavaScript всё является объектами. Числа — это объекты, функции — это объекты, массивы — это объекты, … и даже объекты — это объекты (если тебе пока это не понятно, то не загружай голову, читай дальше).
Если всё вокруг объекты, тогда должен быть какой-то один родительский объект от которого происходят все другие объекты. Да, такой объект существует. Он называется «глобальный объект«. От глобального объекта появляются все базовые виды объектов в JavaScript.
Если простыми словами, то есть ты. Ты появился от каких-то родителей. А твои родители от своих родителей. И так далее. Это значит, что между динозаврами и тобой был какой-то один общий предок, от которого пошли все двуногие хомосапиенсы.
В JavaScript всё точно также. Один объект наследуется от другого.
Функции не живут сами по себе
В третьих, когда ты вызываешь какую-либо функцию, то для этой функции всегда вычисляет объект, в контексте которого она вызывается. То есть вызов любой функции (метода) всегда связан с каким то объектом, хочешь ты этого или нет. Так устроен JavaScript.
Если простыми словами, то функции — это как глаголы в русском языке. Каждая функция — это какое-то действие. Послушай вот эти варианты глаголов:
- проснулся
- походил
- почистил
- поел
- поспал
- потупил
- поехал
Согласись, что в этих глаголах чего-то не хватает. То есть, действие осуществляется, но кто его инициатор?
У любого глагола всегда есть какое-то существительное. Тебе будет гораздо легче воспринимать их, если добавить информации:
- Я проснулся
- Отец походил по комнате
- Дед почитал свои брюки
- Брат поел завтрак
- Сокурсник поспал на паре
- Двоюродный брат потупил в приставку
- Водитель поехал за продуктами
В общем, любое действие из реального мира всегда сопровождается каким-то объектом (живым или не живым, неважно). В JavaScript всё точно также. Вызов любой функции связан с каким-то объектом. И вот мы подходим к самой сути. С каким объектом?
Простой пример использования this
Представь, что ты открыл редактор кода и написал в файле всего одну функцию. Или ты ввёл эту функцию на вкладке «console» в браузере.
function get_this_obj(){ return this }
Если ты сейчас вызовешь эту функцию в браузере, то ты увидишь объект window.
get_this_obj()
То есть, в момент вызова этой функции в коде, вызов был сделан на самом верхнем уровне видимости, а не где-то в блоках вложенности.
В момент вызова this был высчитан и вернулся window. Так вот window — это и есть тот самый «глобальный объект«, от которого происходят все остальные объекты. За ключевым словом ЭТОТ (this) — скрывается ГЛОБАЛЬНЫЙ ОБЪЕКТ.
Объект называется ГЛОБАЛЬНЫМ, потому что он и его ключи доступны из любого места программы. К нему можно обратиться из любого блока.
Как так получилось?
В тот самый момент, когда ты дал имя своей функции, тогда у глобального объекта появился ключ с таким же названием.
То есть, у объекта window появился ключ get_this_obj, который в значении хранит функцию. У объекта window появилось новое свойство. Поэтому, когда вызов осуществился без написания какого-либо имени объекта, тогда «среда выполнения кода» поняла, что это объект window и вернула его вместо ЭТОТ (this).
Если мы где-то в коде программы вызываем функцию по имени, то знай, что по факту мы обращаемся свойству глобального объекта.
А теперь представь, что мы создали свой собственный объект и в один из его ключей положили ссылку на нашу ранее созданную функцию.
let obj = {a:1, b:2, c:3, f:get_this_obj}
Обрати внимание! Три свойства имеют простые значения 1, 2 и 3. Объект «obj» имеет всего один функциональный ключ «f«. Под этим ключом лежит наша функция get_this_obj.
Давай вызовем эту функцию в контексте объекта «obj«, а не window. То есть, давай обратимся к значению ключа «f» и допишем круглые скобки для вызова.
Что получится?
obj.f()
Скриншот:
В этот раз одна и та же функция вернула нам другое значение вместо this. В этот раз нам вернулся сам объект «obj«, потому что мы вызвали эту функцию в контексте этого объекта.
В этом и заключается вся суть ключевого слова this. Оно просто указывает на тот объект, в контексте которого вызывается функция.
Зачем нужен this в JavaScript и как его использовать?
Представь, что ты хочешь работать с прямоугольниками. У тебя есть какие-то данные в количестве миллиона штук и ты бы хотел с ними как-то удобно взаимодействовать.
Ты можешь создать свой собственный конструктор объектов прямоугольников в JavaScript.
class Прямоугольник{
constructor(ш, д){
this.ширина = ш,
this.длина = д
}
площадь(){return this.ширина * this.длина}
половина_площади(){return this.площадь()/2}
};
Для удобства я назвал русскими именами ключи, чтобы тебе было легче воспринимать эту информацию.
Внутри класса есть функция-конструктор, которая создаёт новые объекты. В нашем случае она принимает 2 параметра — это длина и ширина будущего объекта.
Выражение «this.ширина» говорит нам о том, что в новом объекте будет ключ «ширина«, со значением из «ш«.
Выражение «this.длина» говорит нам о том, что в новом объекте будет ключ «длина«, со значением из «д«.
Выражение «площадь(){return this.ширина * this.длина}«, говорит о том, что новый объект унаследует от своего родительского объекта метод, который называется «площадь«. Этот метод будет возвращать площадь нового прямоугольника.
Обратите внимание!!! Мы не пишем никакого имени для нового объекта прямоугольника. Вместо этого мы используем ключевое слово this, которое будет ссылаться на новый объект прямоугольника. Мы абстрагируемся от имён самих прямоугольников и просто пишем общую формулу их создания.
Теперь давайте создадим новый прямоугольник через наш класс.
let пр = new Прямоугольник(2, 10);
А теперь обратимся к функциональному свойству у этого нового объекта.
пр.площадь();
И мы получаем произведение длины данного нового прямоугольника на его ширину — 20.
А также можем получить половину от его площади. Будет — 10
пр.половина_площади();
Скриншот с классом, новым объектом и получением значений площади:
Возвращаясь к миллиону штук данных. Допустим они выглядят так:
let сырые_данные = [[1,2],[3,5],[4,16],[6,77]];
Мы можем пройти по каждой паре и создать новый объект прямоугольника.
let готовые_данные = сырые_данные.map(i => new Прямоугольник(...i));
Теперь, когда у нас есть объекты готовых прямоугольников, мы можем получить массив из их площадей.
let площади = готовые_данные.map(i=>i.площадь());
Важно то, что площадь была вычислена для каждого объекта прямоугольника индивидуально. А если вы помните, мы нигде не указывали имён объектов. Мы писали общую функцию «площадь()«.
Ключевое слово this в функции «площадь()» ссылалось на каждый уникальный объект нового прямоугольника при расчёте его площади. Эти объекты изолированы друг от друга.
В момент вызова «площадь()«, каждый this рассчитался для того объекта в контексте которого эта функция была вызвана.
Вот это и есть понятие ЭТОТ — this.
Информационные ссылки
Официальная страница стандарта ECMAScript — https://tc39.es/ecma262/multipage/ — https://tc39.es/ecma262/