Коротко о this в функциях javascript

от автора

Предисловие

На просторах интернета довольно много информации о том, как работает this, но мне всё время не хватало буквально чуть-чуть, чтобы до конца в этом разобраться.

Недавно я все же, как мне кажется, сделал это и хотел бы поделиться с вами.

Без лишних слов

Мы разберем как простые, так и сложные примеры — так что всем будет интересно.

Два основных тезиса, которые мы рассмотрим:

(1) Для функций, объявленных через function(){}, this вычисляется в момент вызова.
(2) Для стрелочных функций this определяется в момент создания функции.

Начнем с простых примеров.

function globalFunc() {   console.log(this); } const globalArrowFunc = () => {   // создали функцию в глобальной области видимости, где this - window/undefind   // мы будем полагать, что включен use strict и глобально this === undefind   console.log(this); }  globalFunc(); // undefind globalArrowFunc(); // undefind 

А что, если мы добавим эти функции в объекта:

const cat = {   name: 'Pirate',   globalFunc,   globalArrowFunc };  cat.globalFunc(); // { name: 'Pirate', ... } cat.globalArrowFunc(); // undefind 

Давайте разберемся.

Вызов cat.globalFunc() вернул нам объект cat. Для простоты понимания, можно рассматривать это так «this, при вызове функций, объявленных через function(){}, будет равен объекту перед точкой».

Тогда почему cat.globalArrowFunc() вернул нам undefind? Дело в том, что значение this для стрелочной функции определяется в момент ее создания, а, когда мы ее создавали, значение this было undefind.

Теперь давайте создадим объект с парой методов:

const dog = {   name: 'Viking',   // для наглядности мы не будем использовать сокращенный синтаксис   // но с ним было бы тоже самое   localFunc: function() {     console.log(this);   },   localArrowFunc: () => {     console.log(this);   } };  dog.localFunc(); // { name: 'Viking', ... } dog.localArrowFunc(); // undefind 

Почему так?

dog.localFunc() — потому что объект перед точкой dog.
dog.localArrowFunc() — потому что внутри объекта this — это тоже глобальный объект, а значит мы получаем undefind.

Давайте немного усложним наш пример.

const dog = {   name: 'Viking',   localFunc: function() {     const arrowFuncInLocalFunc = () => {       console.log(this);     };     function funcInLocalFunc() {       console.log(this);     };     arrowFuncInLocalFunc(); // 1     funcInLocalFunc(); // 2   },   localArrowFunc: () => {     const arrowFuncInLocalArrowFunc = () => {       console.log(this);     };     function funcInLocalArrowFunc() {       console.log(this);     };     arrowFuncInLocalArrowFunc(); // 3     funcInLocalArrowFunc(); // 4   } };  dog.localFunc(); // 1 - { name: 'Viking', ... } // 2 - undefind dog.localArrowFunc(); // 3 - undefind // 4 - undefind 

Давайте разбираться!

(1) arrowFuncInLocalFunc() // { name: ‘Viking’,… }

Почему так происходит?

Потому что, когда мы создавали объект, мы записали ему функцию localFunc. А, как мы помним из предыдущих примеров, для нее this — это объект перед точкой, то есть { name: ‘Viking’,… }. Теперь поговорим про саму функцию arrowFuncInLocalFunc — она создается непосредственно в момент вызова localFunc и запоминает значение this, которое было в месте ее создания. Таким образом мы получаем, что arrowFuncInLocalFunc возвращает нам { name: ‘Viking’,… }.

(2) funcInLocalFunc() // undefind

Почему так происходит?

Как мы говорили ранее, для функций, объявленных через function(){} значение this определяется в момент вызова и равно объекту перед точкой. В данном случае у нас нет объекта перед точкой, а значит this — глобальный объект или, в нашем случае, undefind.

(3) arrowFuncInLocalArrowFunc() // undefind

Почему так происходит?

Этот пример очень похож на (1), только наша функция arrowFuncInLocalArrowFunc создается внутри такой же стрелочной функции. Также мы помним, что стрелочные фукнции в момент объявления записывают в this значение из своего окружения. Однако, наша функция была создана внутри localArrowFunc, для которой this — undefind. А значит и для arrowFuncInLocalArrowFunc this будет равен undefind.

(4) funcInLocalArrowFunc() // undefind

Почему так происходит?

Точно по той же причине, что и в пункте (2) для funcInLocalFunc

Давайте рассмотрим еще один пример:

const cat = {   name: 'Tom',   getFuncWithTimName: function() {     return () => {       console.log(this.name);     }   } };  const mouse = {   name: 'Jerry',   logName: cat.getFuncWithTimName() };  mouse.logName(); // Tom o_O !? 

Так происходит потому что getFuncWithTimName создает и возвращает стрелочную функцию, а в момент создания стрелочной функции this тот же самый, что и у getFuncWithTimName. А для getFuncWithTimName this — это объект перед точкой (cat).

Итого

Контекст для стрелочных функци определяется в момент их создания.

Контекст для function(){} определяется в момент их вызова и равен объекту перед точкой.

ссылка на оригинал статьи https://habr.com/ru/post/515356/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *