Javascript use this in function

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

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

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

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

Начнем с определения.

This — это ссылка на контекст исполнения функции. Таким образом получается, что this тесно связан именно с функциями и рассматривается относительно них. Вне функции this будет ссылаться на глобальный контекст

Тезис 1
Для функций, объявленных через function f( ) , this вычисляется в момент вызова и равен объекту перед точкой. Если такого объекта нет — тогда this будет указывать на глобальный контекст (window)

Тезис 2
Для стрелочных функций this определяется в момент их создания и больше никогда не изменяется

Договоримся, что везде используется ‘use strict’ , поэтому в глобальной области видимости this всегда будет undefined , а не window .

Пример 1

Для начала посмотрим на самый простой пример.

function globalFunc() < console.log(this); >const globalArrowFunc = () => < console.log(this); >console.log(this); // ? globalFunc(); // ? globalArrowFunc(); // ? 
console.log(this); // undefined 

Простое обращение к this указывает на ближайший контекст исполнения — window.

Функция, объявленная через function, указывает на window, потому что нет никакого объекта перед точкой.

globalArrowFunc(); // undefined 

Стрелочная функция указывает на window, потому что она была создана внутри глобального контекста (window).

Пример 2

Давайте двинемся дальше и рассмотрим всё то же самое внутри объекта.

const user = < name: 'Bob', userThis: this, func() < console.log(this); >, arrowFunc: () => < console.log(this); >>; console.log(user.userThis); // ? user.func(); // ? user.arrowFunc(); // ? 
console.log(user.userThis); // undefined 

Здесь мы вновь обратим свое внимание на то, что this имеет смысл только относительно функции, потому что this указывает на контекст исполнения функции. Поскольку этот объект находится внутри глобального контекста (window), то и наше this указывает на window.

Здесь объектом перед точкой является user, поэтому this ссылается на объект user.

Поскольку стрелочная функция запомнила свой контекст в момент создания, то и при вызове она будет ссылаться именно на него. Таким образом мы получаем window.
Однако вы можете задать вопрос «Но почему в момент создания контекст был window, а не объект, внутри которого она была объявлена как метод?».
Стрелочная функция в момент создания ищет ближайший к ней контекст и запоминает его, а он у нас точно такой же как и в случае простого присвоения внутри user.userThis .

Пример 3

А теперь давайте попробуем что-то посложнее. Создадим объект с методами, которые возвращают другие функции. Таким образом у нас получится 4 разных метода.

Обычная функция, возвращающая обычную функцию — funcFunc.
Обычная функция, возвращающая стрелочную функцию — funcArrow.
Стрелочная функция, возвращающая обычную функцию — arrowFunc.
Стрелочная функция, возвращающая стрелочную функцию — arrowArrow.

const user = < name: 'Bob', funcFunc() < return function() < console.log(this); >>, funcArrow() < return () => < console.log(this); >>, arrowFunc: () => < return function() < console.log(this); >>, arrowArrow: () => < return () => < console.log(this); >>, >; user.funcFunc()(); // ? user.funcArrow()(); // ? user.arrowFunc()(); // ? user.arrowArrow()(); // ? 

Когда вызывается user.funcFunc() — нам возвращается функция function. Обратим внимание, что мы сразу же вызываем ее и в этот момент у нее нет никакого объекта перед точкой, а значит this ссылается на window.
Мы могли бы разбить это на 2 строки
const foo = user.funcFunc()
foo(); — нет объекта перед точкой

Когда мы вызвали метод funcArrow, то создали стрелочную функцию и в момент создания она запомнила окружающий ее контекст. Теперь она всегда будет его возвращать и никогда не потеряет.

Здесь все то же самое, что и первом примере. Нам не важно, каким образом была создана function. Важно лишь что в момент ее вызова у нее нет объекта перед точкой.

user.arrowArrow()(); // undefined 

Как мы помним, внутри метода arrowArrow this указывал на window. Таким образом и только что созданная стрелочная функция будет указывать на него же.

Пример 4

Давайте еще немного поиграем с предыдущим примером. Теперь мы не просто вытащим новые функции и вызовем их, а запишем их в другой объект и вызовем из него.

// Объект user остался без изменений const user = < name: 'Bob', funcFunc() < return function() < console.log(this); >>, funcArrow() < return () => < console.log(this); >>, arrowFunc: () => < return function() < console.log(this); >>, arrowArrow: () => < return () => < console.log(this); >>, >; const user2 = < name: 'Jim', funcFunc: user.funcFunc(), funcArrow: user.funcArrow(), arrowFunc: user.arrowFunc(), arrowArrow: user.arrowArrow() >user2.funcFunc(); // ? user2.funcArrow(); // ? user2.arrowFunc(); // ? user2.arrowArrow(); // ? 

В момент вызова перед точкой объект user2, поэтому на него и будет ссылаться this .

Когда мы вызвали user.funcArrow(), мы создали новую стрелочную функцию, но в момент создания она запомнила ближайший к ней контекст (user) и теперь она всегда и везде будет возвращать именно его.

Здесь точно то же самое, что и в первом случае. Мы вернули функци и вызвали ее. Объект перед точкой user2, поэтому this указывает именно на него.

user2.arrowArrow(); // undefined 

Когда мы вызвали user.arrowArrow(), то создали стрелочную функцию, которая запомнила ближайший контекст (window). Теперь она всегда будет указывать на него.

Ну вот и всё

Надеюсь, что после прочтения данного материала, определение контекста исполнения уже не так пугает вас, как раньше 🙂

Источник

Ключевое слово this в javascript — учимся определять контекст на практике

По просьбам некоторых читателей решил написать топик про контекст в javascript. Новички javascript часто не понимают значение ключевого слова this в javascript. Данный топик будет интересен не только новичкам, а также тем, кто просто хочет освежить данный аспект в памяти. Посмотрите пример ниже. Если вы затрудняетесь ответить на вопрос «что будет выведено в логе» хотя бы в одном из пунктов или хотите просто посмотреть ответы — добро пожаловать под кат.

var f = function() < this.x = 5; (function() < this.x = 3; >)(); console.log(this.x); >; var obj = >; f(); new f(); obj.m(); new obj.m(); f.call(f); obj.m.call(f); 

1. Теория

В отличие от многих других языков программирования ключевое слово this в javascript не привязывается к объекту, а зависит от контекста вызова. Для упрощения понимания будем рассматривать примеры применительно к браузеру, где глобальным объектом является window.

1.1. Простой вызов функции

В данном случае this внутри функции f равен глобальному объекту (например, в браузере это window, в Node.js — global).

Самовызывающиеся функции (self-invoking) работают по точно такому же принципу.

1.2. В конструкторе
function f() < this.x = 5; console.log(this === window); // false >var o = new f(); console.log(o.x === 5); // true 

При вызове функции с использованием ключевого слова new функция выступает в роли конструктора, и в данном случе this указывает на создаваемый объект.

1.3. В методе объекта
var o = < f: function() < return this; >> console.log(o.f() === o); // true 

Если функция запускается как свойство объекта, то в this будет ссылка на этот объект. При этом не имеет значения, откуда данная функция появилась в объекте, главное — как она вызывается, а именно какой объект стоит перед вызовом функции:

var o = < f: function() < return this; >> var o2 = ; console.log(o.f() === o);//true console.log(o2.f() === o2);//true 
1.4. Методы apply, call

Методы apply и call позволяют задать контекст для выполняемой функции. Разница между apply и call — только в способе передачи параметров в функцию. Первый параметр обеих функций определяет контекст выполнения функции (то, чему будет равен this).

function f(a,b,c) < return a * b + c; >f.call(f, 1, 2, 3); // аргументы перечисляются через запятую; var args = [1,2,3]; f.apply(f, args); // // аргументы передаются в виде массива; // В обоих случаях вызовется функция f с аргументами a = 1, b = 2, c = 3; 
function f() < >f.call(window); // this внутри функции f будет ссылаться на объект window f.call(f); //this внутри f будет ссылаться на f 
function f() < console.log(this.toString()); // 123 >f.call(123); // this внутри функции f будет ссылаться на объект Number со значением 123 

2. Разбираем задачу

Применим полученные знания к приведенной в начале топика задаче. Опять же для упрощения будем рассматривать примеры применительно к браузеру, где глобальным объектом является window.

2.1. f()
var f = function() < // Функция f вызывается с помощью простого вызова - f(), // поэтому this ссылается на глобальный объект this.x = 5; // window.x = 5; // В пункте 1.1 также указано, что в самовызывающихся функциях this также ссылается на глобальный объект (function() < this.x = 3; // window.x = 3 >)(); console.log(this.x); // console.log(window.x) >; 
2.2. new f();
var f = function() < // Функция f вызывается с использованием ключевого слова new, // поэтому this ссылается на создаваемый объект (обозначим его как object) this.x = 5; // object.x = 5; // В пункте 1.1 также указано, что в самовызывающихся функциях this ссылается на глобальный объект (function() < this.x = 3; // window.x = 3 >)(); console.log(this.x); // console.log(object.x) >; 
2.3. obj.m();
2.4. new obj.m();
2.5. f.call(f);
var f = function() < // Функция f вызывается с помощью метода call // первым параметром в call указана сама функция (точнее объект) f, поэтому // поэтому this ссылается на f this.x = 5; // f.x = 5; // В пункте 1.1 также указано, что в самовызывающихся функциях this ссылается на глобальный объект (function() < this.x = 3; // window.x = 3 >)(); console.log(this.x); // console.log(f.x) >; 
2.6. obj.m.call(f);

Внимание: Если данный пример рассматривать отдельно от остальных, то в логе будет не 5, а undefined. Попробуйте внимательно разобрать пример и объяснить поведение

var f = function() < this.x = 5; (function() < this.x = 3; >)(); console.log(this.x); >; var obj = >; obj.m.call(f); 

Вместо заключения

В статье я постарался описать, как работает ключевое слово this в javascript. В ближайшее время я скорее всего напишу статью, в которой описывается для чего нужно знать эти тонкости (например, jQuery.proxy)

P.S. Если вы заметили ошибки/неточности или хотите что-то уточнить/добавить — напишите в ЛС, поправлю.

Источник

Читайте также:  Основы машинного обучения на python
Оцените статью