Как стать автором
Обновить
1165.3
OTUS
Цифровые навыки от ведущих экспертов

Слово this: управление контекстом выполнения в JavaScript

Время на прочтение5 мин
Количество просмотров1K

Привет, Хабр! Сегодня мы поговорим о this, потому что без четкого понимания, как работает this, ваш код может стать источником путаницы и ошибок.

this в JS — это ключевое слово, которое ссылается на текущий контекст выполнения. Его значение зависит от того, где и как была вызвана функция, а не от того, где она была определена.

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

Разные контексты this

Глобальный контекст: поведение this вне функций

Когда вы находитесь на верхнем уровне кода — без функций и объектов — this ссылается на глобальный объект. В браузерах это window, а в Node.js — global.

console.log(this); // В браузере выведет объект window

Здесь this ссылается на глобальный объект. Если вы используете this вне любого контекста, вы всегда получите глобальный объект.

Но как это повлияет на функции? Рассмотрим следующий пример:

function showContext() {
    console.log(this);
}

showContext(); // Вызовет функцию, выведет window (или global в Node.js)

Согласитесь, такое поведение может удивить, особенно если вы ожидали, что this будет ссылаться на что-то другое. Если вы хотите, чтобы this указывал на конкретный объект в глобальном контексте, нужно обернуть его в другой объект:

const myObject = {
    name: 'My Object',
    showContext: showContext,
};

myObject.showContext(); // выведет myObject

Объектный контекст: как this ссылается на текущий объект в методах

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

const user = {
    name: 'Алина',
    greet() {
        console.log(`Hello, my name is ${this.name}`);
    },
};

user.greet(); // Hello, my name is Алина

В этом примере, когда greet() вызывается, this ссылается на объект user, и мы получаем доступ к его свойствам. Но что происходит, если мы передадим метод в другую функцию?

const greetFunc = user.greet;
greetFunc(); // Hello, my name is undefined

Здесь this больше не указывает на user, потому что метод был вызван вне контекста объекта.

Функциональный контекст

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

function showThis() {
    console.log(this);
}

showThis(); // window (или undefined в strict mode)

Но если вы вызываете функцию как метод объекта, this будет ссылаться на объект:

const obj = {
    value: 42,
    showValue() {
        console.log(this.value);
    },
};

obj.showValue(); // 42

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

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

const person = {
    name: 'Николай',
    greet: function () {
        const arrowFunc = () => {
            console.log(`Hi, I'm ${this.name}`);
        };
        arrowFunc();
    },
};

person.greet(); // Hi, I'm Николай

Здесь стрелочная функция arrowFunc сохраняет контекст this, который указывает на объект person.

Однако будьте осторожны: если вы попробуете использовать стрелочную функцию в методах объектов, это приведет к тому, что this не будет ссылаться на объект:

const obj = {
    name: 'Ирина',
    show: () => {
        console.log(this.name);
    },
};

obj.show(); // undefined

Здесь this ссылается на глобальный объект (или undefined в строгом режиме), и вы не получите ожидаемого результата.

Изменение контекста выполнения

Теперь посмотрим, как управлять контекстом выполнения с помощью методов call, apply и bind. Эти инструменты позволяют настраивать, на что ссылается this, в зависимости от вашего желания.

Методы call, apply и bind: как и когда их использовать для управления контекстом

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

const person = {
    name: 'Артур',
};

function greet(greeting) {
    console.log(`${greeting}, my name is ${this.name}`);
}

greet.call(person, 'Hello'); // Hello, my name is Артур

Используем call, чтобы указать, что this в функции greet ссылается на объект person. Мы также передаем аргумент 'Hello', который функция использует.

Метод apply работает аналогично call, но принимает аргументы в виде массива.

const person = {
    name: 'Никита',
};

function greet(greeting, punctuation) {
    console.log(`${greeting}, my name is ${this.name}${punctuation}`);
}

greet.apply(person, ['Hi', '!']); // Hi, my name is Никита!

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

const boundFunction = func.bind(thisArg, arg1, arg2, ...);
const person = {
    name: 'Ирина',
};

function greet(greeting) {
    console.log(`${greeting}, my name is ${this.name}`);
}

const greetIrina = greet.bind(person);
greetIrina('Hey'); // Hey, my name is Ирина

Здесь создаем новую функцию greetIrina, которая всегда будет ссылаться на объект person.

Классы и контекст: как работать с this в классах

Когда мы работаем с классами в JavaScript, важно помнить, что this в методах классов указывает на экземпляр класса. Однако, если вы передаете метод класса как коллбэк, this может потеряться.

Пример:

class Person {
    constructor(name) {
        this.name = name;
        this.greet = this.greet.bind(this); // Привязываем контекст
    }

    greet() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

const artem = new Person('Артем');
setTimeout(artem.greet, 1000); // Hello, my name is Артем

Здесь используем bind в конструкторе, чтобы убедиться, что this всегда ссылается на экземпляр Person, даже если метод вызывается вне контекста класса. Если бы мы не использовали bind, мы бы получили undefined в this.name при вызове greet через setTimeout.

Прочие фичи

Строгий режим: предотвращение неожиданных значений this

Строгий режим — это способ задать правила, которые помогают избежать ошибок, упрощают диагностику и повышают безопасность кода. В строгом режиме, если функция вызывается без контекста (как обычная функция), this будет undefined, а не ссылаться на глобальный объект.

function showThis() {
    console.log(this);
}

showThis(); // В браузере выведет window

Пример со строгим режимом:

'use strict';

function showThis() {
    console.log(this);
}

showThis(); // undefined

Методы объектов и this

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

Пример:

const obj = {
    name: 'Ирина',
    showName() {
        console.log(this.name);
    },
};

const show = obj.showName;
show(); // undefined (в строгом режиме) или 'Ирина' (в обычном)

Здесь, когда мы вызываем show, this не указывает на obj, что и приводит к неожиданным результатам.

this в обработчиках событий

Когда вы добавляете обработчик события, this в нем обычно ссылается на

элемент, на который установлено событие.

Пример:

<button id="myButton">Click me</button>

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

Пример со стрелочной функцией:

<button id="myButton">Click me</button>

Неявный и явный this

JavaScript различает неявный и явный this. Неявный this — это когда this определяется автоматически в зависимости от того, как функция была вызвана. Явный this — это когда вы используете методы call, apply или bind, чтобы явно указать, на что ссылается this.

Неявный this:

const car = {
    brand: 'Ford',
    showBrand() {
        console.log(this.brand);
    },
};

car.showBrand(); // Ford

Явный this:

function showBrand() {
    console.log(this.brand);
}

const myCar = { brand: 'Toyota' };

showBrand.call(myCar); // Toyota

Пусть ваш код будет ясным, а this под контролем. Помните, что this — штука капризная, но, как любой хороший инструмент, в умелых руках творит чудеса.


Больше про языки программирования эксперты OTUS рассказывают в рамках практических онлайн-курсов. С полным каталогом курсов можно ознакомиться по ссылке.

Теги:
Хабы:
+1
Комментарии4

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS