Многоликий this в JS

Многоликий this в JS

В этом посте я сделаю все возможное, чтобы объяснить одну из самых фундаментальных частей JavaScript: контекст выполнения. Если вы много используете JS-фреймворки, понимание «this» может сначала показаться приятным дополнением. Однако, если вы собираетесь серьезно относиться к программированию, понимание контекста абсолютно важно для того, чтобы быть JavaScript программистом.

Мы используем this во многом так же, как мы используем его на естественном языке. Мы предпочли бы написать «Моя мама посинела, это очень тревожно», вместо «Моя мама посинела. Становление моей мамы синей очень беспокоит». Зная контекст this, мы можем понять, что нас так беспокоит.

Попробуем соединить его с языком программирования. В JavaScript мы используем this как ярлык, ссылку. Он относится к объектам, переменным, и мы используем их в контексте.

Это очень тревожно, но не бойтесь. Через минуту все станет ясно.

Глобальный контекст

Что вы думаете, если кто-нибудь скажет: «Это очень тревожно»? Без какой-либо заметной причины, так же, как начало разговора, без контекста или введения. Скорее всего, вы начнете связывать это с чем-то вокруг или с последней ситуацией.

Это происходит в браузере постоянно. Сотни тысяч разработчиков используют this без контекста. Наш бедный браузер делает все возможное, чтобы соотнести this применительно к глобальному объекту, window в этом конкретном примере.

Вне любой функции в глобальном контексте выполнения this относится к глобальному контексту (объекту window).

Контекст функции

Чтобы снова обратиться к реальному примеру, контекст функции можно воспринимать как контекст предложения. «Моя мама посинела, это очень тревожно». Мы использовали this в предложении, поэтому мы знаем, что это значит, но мы можем использовать его и в разных предложениях. Например: «Ураган грядет, это очень тревожно». То же самое, но другой контекст и совершенно другое значение.

Контекст в JavaScript связан с объектами. Он ссылается на объект внутри выполняемой функции. this относится к объекту, в котором выполняется функция.

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

Когда функция вызывается как метод объекта, она ссылается на объект, который вызывал метод.

True - Мы все еще находимся в глобальном контексте.
False - функция вызывается как метод объекта.
True - функция вызывается как метод объекта.
False - Функция вызывается как метод объекта y_obj, поэтому this его контекст.

Example 4

В строгом режиме (strict mode) правила разнятся. Контекст остается таким, каким он был установлен. В этом конкретном примере this не был определен, поэтому он остается undefined.

Example 5

Как и в предыдущем примере, функция вызывается как метод объекта, независимо от того, как он был определен.

Example 6

this является динамическим, то есть он может меняться от одного объекта к другому

Example 7

Мы можем назвать фрукты this по имени объекта.

Example 8

Итак, new измененяет правила. Оператор new создает экземпляр объекта. Контекст функции будет ссылаться на созданный экземпляр объекта.

Call, apply, bind

Реальный пример: «Это очень тревожит - факт того, что моя мама посинела».

Эти методы позволяют нам выполнять любую функцию в любом желаемом контексте. Посмотрим, как они работают, на примерах.

Example 1

xo xo - Мы назвали тест в глобальном контексте.
lorem ipsum - Используя вызов, мы вызываем тест в контексте foo.
lorem ipsum - Используя apply, мы вызываем тест в контексте foo.
Эти два метода позволяют выполнять функцию в любом желаемом контексте.

apply позволяет вызывать функцию с аргументами в виде массива, тогда как call требует, чтобы параметры были явно указаны.

Example 2

Undefined - В объекте документа нет переменной.
Undefined - В объекте документа нет переменной. В этой ситуации вызов не может изменить контекст.
15 - Мы создали новый объект {a: 15} и вызвали test в этом контексте.

Метод bind устанавливает постоянный контекст в требуемое значение.
После использования bind this неизменяемо даже при вызове call, apply или bind.

Стрелочные функции (ES6)

Стрелочные функции были введены как фича ES6. Их можно рассматривать как очень удобный инструмент. Однако, вы должны знать, что стрелочные функции работают иначе, чем обычные функции с точки зрения контекста. Посмотрим.

Example 1

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

Example 2

Обратите внимание на разницу между стрелочной и обычной функцией. Сo стрелочной функцией мы находимся в контексте window.
Можно сказать, что:

    x => this.y равно function(x) {return this.y}.bind(this)

Стрелочная функция всегда имеет значение this и поэтому не может использоваться как конструктор. Этот последний пример иллюстрирует разницу.

Example 3

Что почитать

http://www.joshuakehn.com/2011/10/20/Understanding-JavaScript-Context.html

http://ryanmorr.com/understanding-scope-and-context-in-javascript/

https://hackernoon.com/execution-context-in-javascript-319dd72e8e2c

http://2ality.com/2012/04/arrow-functions.html

Присоединяйтесь к нашим каналам FrontEndDev и Web Stack в Telegram, чтобы не пропустить самое интересное!

Оригинал статьи The many faces of this in javascript