Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Контекст (This) JS: Введение в ООП

Что же такое методы? В JavaScript методами называют функции, записанные в свойства объектов. Фактически метод – это роль, которую выполняет функция будучи привязанной к объекту.

В других языках другие определения и принципы работы

В JavaScript функции это объекты первого рода, то есть они ведут себя как данные: их можно записывать в переменные или константы. Свойства объектов подобны переменным, а значит в них можно сохранить функции:

const company = { name: 'Hexlet' };
// Создание функции, которая сразу же присваивается свойству getName и становится методом
company.getName = () => 'Hexlet'; // Функция возвращает строку "Hexlet"

// Вызов метода
company.getName(); // "Hexlet"

Это всего лишь один из множества возможных вариантов добавления функции в объект. Ниже еще несколько примеров:

// При создании объекта
const obj = {
  getName: () => 'Hexlet',
};

// Через присваивание константы
const company = { name: 'Hexlet' };
// Имя константы не принципиально
const getHexlet = () => 'Hexlet';
company.getName = getHexlet; 

// Кстати никто не мешает вызывать функцию напрямую без объекта
getHexlet();
// Или даже так
const getName = company.getName;
getName(); // "Hexlet"

Все варианты выше эквивалентны. Они приводят к одному и тому же результату. Однако, смысла в таком результате мало. Метод возвращает строку и никак не использует данные объекта.

const company = { name: 'Hexlet' };
company.getName = () => 'Hexlet';

company.getName(); // "Hexlet"
company.name = 'Hexlet Plus';
// Имя поменяли, но возврат остался прежний
company.getName(); // "Hexlet"

Для доступа к данным объекта внутри метода используется новое ключевое слово this. Внутри методов оно ссылается на текущий объект, к которому привязан метод. Правда так this работает только для обычных функций. У стрелочных другой принцип. Это главное различие между стрелочными и обычными функциями, которое мы рассмотрим подробнее в одном из следующих уроков. А здесь, все дальнейшие примеры будут приводиться с использованием обычных именованных функций. Ранее мы их частично рассматривали в уроке Способы записи функций

this – одна из самых сложных и запутанных тем в JavaScript для новичков. Мало того, что он работает совсем не так как this в других языках, так еще и внутри самого JavaScript у него множество неочевидных вариантов поведения.

const company = { name: 'Hexlet', employees: [] };
// Методы, извлекающие данные из объекта называются геттерами
// Поэкспериментируйте со стрелочной функцией, убедитесь, что она работает по-другому
company.getName = function getName() {
  return this.name;
};

// Обязательно потренируйтесь на repl.it
company.getName(); // Hexlet

company.name = 'Hexlet Plus';
company.getName(); // Hexlet Plus

this дает возможность не только читать данные, но и менять их:

// Методы меняющие данные объекта называют сеттерами
company.setName = function setName(name) {
  this.name = name;
};

// Добавление нового сотрудника
company.addEmployee = function addEmployee(user) {
  // Важно, что на момент вызова, employees уже добавлен в company
  this.employees.push(user);
};

// Обязательно потренируйтесь на repl.it
company.getName(); // Hexlet

company.setName('Hexlet Plus');
company.getName(); // Hexlet Plus

const user = { name: 'Petya' };
company.addEmployee(user);
company.employees; // [{ name: 'Petya' }]

Как видно из кода выше, свойства можно менять как напрямую так и из методов. Какой способ предпочесть – зависит от ситуации. Если в коде строится абстракция, то, вероятно, хорошим решением станут отдельные сеттеры, это, в том числе, важно для соблюдения инвариантов.

Контекст

Выше, когда давалось определение this, говорилось, что this ссылается на текущий объект, к которому привязан метод. И здесь кроется ключевое отличие this в JavaScript от this в других языках. В JavaScript this у метода может измениться:

const company1 = { name: 'Hexlet', getName: function getName() { return this.name } };
const company2 = { name: 'Hexlet Plus' };

company1.getName(); // "Hexlet"

// Копируется ссылка на функцию, а не сама функция
// Сама функция существует независимо от этих объектов
company2.getName = company1.getName;
company2.getName(); // "Hexlet Plus"

Что здесь произошло? Вызов функции из другого объекта привел к смене объекта, на который ссылается this. Эта особенность называется поздним связыванием. Значение this вычисляется не во время определения кода, а во время обращения к этому идентификатору.

Лучше всего можно понять эту особенность, познакомившись с тем, как вызываются функции внутри самого JavaScript и откуда там берется this. Так как в JavaScript функции это тоже объекты (сюрприз!), то у них есть свои методы. Среди них есть метод call(), который и используется для вызова:

const sayHi = () => 'Hi!';
sayHi.call(); // "Hi!"

Зачем так сделано? Дело в том, что первым параметром эта функция принимает контекст - объект, на который и будет ссылаться this внутри функции (и для этого ей не обязательно быть методом):

const getName = function getName() {
  return this.name;
};

const company1 = { name: 'Hexlet' };
getName.call(company1); // "Hexlet"

const company2 = { name: 'Hexlet Plus' };
getName.call(company2); // "Hexlet Plus"

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

Теперь, когда вы знаете как работает this, попробуйте ответить на вопрос, что будет выведено на экран?

const company = {
  name: 'Hexlet',
  country: {
    name: 'Finland',
    getName: function getName() {
      return this.name;
    }
  },
};

console.log(company.country.getName()); // => ?

Правильный ответ: "Finland". Почему? Потому что контекстом для метода getName() является объект country, а не company. Если немного модифицировать код, то понять эту идею станет проще:

const { country } = company;
console.log(country.getName()); // "Finland"

Сокращенное определение методов

Из-за необходимости использовать обычные функции при создании объектов в JavaScript был введен специальный сокращенный синтаксис создания методов при определении объектов:

const company = {
  name: 'Hexlet',
  getName() {
    return this.name;
  },
};

Такой способ – всего лишь "синтаксический сахар". Он позволяет сделать запись чуть короче, но не более того. Главное запомните – это обычная функция, а не стрелочная. В дальнейшем мы будем использовать именно такое определение.


Дополнительные материалы

  1. YDKJS: This

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужна профессиональная подписка

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

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

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

  • 120 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
29 сентября 8 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
29 сентября 8 месяцев

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»