Привет, Хабр. Я Саша, разработчик, пишу на JS. Ранее я рассказывал о callback-функциях, деструктуризации, операторах и многом другом. Если вы уже успели познакомиться с основами JavaScript, то наверняка вам знакомы такие понятия, как объекты и функции.

В этой статье мы двинемся дальше и соберем эти знания воедино. Я расскажу вам о методах объектов и загадочном слове this. Разберемся, для чего они нужны, как сделать объекты по-настоящему живыми и как избежать частых ошибок. Ну что, начнем. 

Я помню, что для многих из вас JavaScript — это первый язык программирования, поэтому я постараюсь объяснять максимально просто и наглядно, как всегда. 

И если вы только начали изучать JS и еще не разобрались, что такое объекты и функции, то настоятельно рекомендую сначала изучить эти темы. Тогда сегодняш��ий материал будет максимально понятным:

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

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

const product = {
 name: "Кофе",
 price: 600,
 count: 2,
};

function getTotalPrice(product) {
 return product.price * product.count;
}

console.log(getTotalPrice(product));
Результат в консоли.
Результат в консоли.

Что здесь происходит

У нас есть объект product, который хранит данные о товаре. Отдельно от него существует функция getTotalPrice, которая для расчетов должна явно получить этот объект. А сама логика расчета тесно связана с объектом, но формально находится снаружи.

Какие здесь минусы

  • Функция и объект существуют отдельно. В большом коде не сразу поймешь, что эта функция работает именно с этим объектом.

  • Неудобство использования. Каждый раз для расчета нужно передавать объект в функцию.

  • Хрупкость. Если структура объекта изменится (например, свойство count переименуется в quantity), придется исправлять все функции, которые с ним работают.

А теперь предлагаю решить эту же задачу с использованием аналогичной функции, но уже в виде метода. Давайте встроим функцию прямо в объект, сделав ее его частью:

const product = {
 name: "Кофе",
 price: 600,
 count: 2,

 getTotalPrice: function () {
   return product.price * product.count;
 }
};

console.log(product.getTotalPrice(product));
Результат в консоли тот же.
Результат в консоли тот же.

Что же изменилось? Функция getTotalPrice теперь находится внутри объекта product. Она стала его неотъемлемой частью. А для ее вызова мы обращаемся к самому объекту через точку: product.getTotalPrice(). Так мы подходим к главному термину.

Метод — это функция, являющаяся свойством объекта. Если свойство хранит функцию, оно называется методом этого объекта.

Чем методы отличаются от обычных функций

Функция существует сама по себе, ее можно вызвать откуда угодно. А метод привязан к объекту. Он описывает действие, которое может совершить этот объект. Вызов метода всегда связан с объектом, к которому он принадлежит — через точку или квадратные скобки.

Вы наверняка заметили странность в коде метода. Да, функция теперь внутри объекта, но для доступа к данным (product.price) она по-прежнему использует внешнюю переменную product:

getTotalPrice: function () {
  return product.price * product.count;
}

Этот подход очень ненадежен. Почему это проблема:

  • если мы переименуем константу product в coffee, метод сразу сломается;

  • если этот объект будет элементом массива, у него не будет внешнего имени product;

  • при передаче объекта в другую функцию мы теряем его исходное имя.

Это осознанный недостаток текущего примера, и именно он подводит нас к необходимости более правильного решения.

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

Бесплатный базовый курс по JS

Рассказываем, как работать с переменными, типами данных, функциями и о многом другом!

Начать изучение →

Что такое this

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

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

this позволяет методу получить доступ к данным своего объекта, не зная и не используя его внешнее имя. Метод становится переносимым и независимым. Он говорит: «Возьми данные у того объекта, который меня вызвал (у моего this), а не ищи какую-то внешнюю переменную product».

Перепишем наш код с использованием this:

const product = {
 name: "Кофе",
 price: 600,
 count: 2,

 getTotalPrice: function () {
   return this.price * this.count;
 }
};

console.log(product.getTotalPrice());
Результат в консоли тот же.
Результат в консоли тот же.

Что изменилось?

  • Вместо product.price мы пишем this.price.

  • Вместо product.count мы пишем this.count.

Когда мы вызываем метод как product.getTotalPrice(), JavaScript понимает, что функция была вызвана в контексте объекта product. Поэтому внутри этой функции слово this автоматически становится ссылкой ��а объект product.

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

Главное правило — this определяется в момент вызова. Значение this не фиксировано. Оно определяется не там, где функция объявлена, а тем, как она была вызвана.

В нашем примере this работает предсказуемо, потому что мы вызываем метод через точку — product.getTotalPrice(). В этом случае this внутри метода и есть product. Но если метод присвоить в константу как ссылку, то this внутри него уже не будет содержать ссылку на этот объект: 

const product = {
 name: "Кофе",
 price: 600,
 count: 2,

 getTotalPrice: function () {
   return this.price * this.count;
 }
};

const getTotalPrice2 =  product.getTotalPrice;

console.log(getTotalPrice2());
Результат в консоли.
Результат в консоли.

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

Практика для закрепления

Вы уже знаете, как создавать методы в объекте. А как обстоят дела с массивом таких объектов? Давайте создадим несколько товаров с помощью функции-конструктора и выведем их в консоль:

// Функция для создания товаров
function createProduct(name, price, count) {
 return {
   name: name,
   price: price,
   count: count,

   getTotalPrice: function() {
     return this.price * this.count;
   },

   getInfo: function() {
     return ${this.name} | ${this.count} шт. | ${this.getTotalPrice()} руб.;
   }
 };
}

// Создаем массив товаров
const products = [
 createProduct("Кофе", 600, 2),
 createProduct("Чай", 300, 3),
 createProduct("Печенье", 150, 5),
 createProduct("Шоколад", 200, 1)
];

// Выводим информацию о каждом товаре в консоль
for (const product of products) {
 console.log(product.getInfo());
}
Результат в консоли.
Результат в консоли.

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

Итог

Сегодня мы сделали важный шаг в изучении JavaScript. Давайте тезисно подчеркнем то, что узнали:

  • методы — это функции внутри объектов, которые делают наши данные живыми;

  • this — это способ метода обратиться к своему объекту без привязки к внешнему имени.

Не переживайте, если тема кажется сложной, уверенность придет с  практикой. Экспериментируйте, пишите код! Попробуйте создать свои объекты с методами, чтобы закрепить знания.

 А впереди нас ждет много интересного: поведение this в стрелочных функциях и разных режимах браузера, а также способы работы с контекстом.

Поведение ключевого слова this в JavaScript существенно зависит от режима выполнения кода. Во избежание ошибок, рекомендую принудительно включать «use strict». 

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

Современные браузеры по умолчанию включают «строгий» режим только при загрузке модулей и в классах.

Жду вас в следующих статьях!

Комментарии (10)


  1. aamonster
    26.11.2025 22:14

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

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

    И начинать его использование, уже умея обходиться без него и понимая, что это такое в js (вообще не то же самое, что в других языках).


    1. vanxant
      26.11.2025 22:14

      "Не так как в Java" ≠ "крайне странно".

      Если в классической java вам надо повесить обработчик нажатия кнопки onClick, вы должны создать аж целый класс с методом onClick, создать объект этого класса и только потом пихнуть его в кнопку. При этом у вас будет совершенно бесполезный this, ссылающийся на бессмысленный объект. В JS вы можете сделать onClick = onClick.bind(this) в нужном вам объекте, который собственно выполняет обработку, и пихнуть в кнопку уже этот метод.

      Ну и да, замыкания под капотом делают именно это же (создают анонимный класс с полями, которые вы захватываете при замыкании). В каких-то случаях такая запись короче, в каких-то нет и приводит к лишним ссылкам.


      1. aamonster
        26.11.2025 22:14

        Так-то я на Java не пишу :-)

        Ссылки на функции, подобные тем, что в JavaScript (когда передаёшь функцию без this), помнится, есть в C++. Вот только там их не вызовешь с неявной передачей this, всегда надо
        (pointer_to_object->*pointer_to_method)(arguments). Невозможно вызвать функцию, требующую this, не передав этот самый this явно (и при этом ещё контроль типов будет).

        Неявная передача this из контекста (когда переданная функция вызывается с текущим значением this, а не явно в неё переданным в вызове типа pointer_to_method.call(this, arg1, arg2, ...) – специфика именно JavaScript. У него просто своеобразная история, вызвавшая именно такие решения – и надо помнить, что в этом он отличается примерно от всех языков.

        К сожалению, даже переход к TypeScript (казалось бы, проверка типов добавилась) проблему не решает – он не предупредит вас о том, что вы вызываете метод объекта MyObject с this=window. Просто надо быть очень осторожным :-)

        ЗЫ: Замыкание, скорей всего, обойдётся чуть дороже bind – но я бы рекомендовал новичкам писать именно его, оставив bind более опытным чувакам.


  1. ermouth
    26.11.2025 22:14

    Значение this не фиксировано

    Не упомянуто, что оно вполне может быть зафиксировано.

    function t(){return this.wow};
    var bound_t = t.bind({wow:true});
    console.log(t()); // undefined
    console.log(bound_t()); // true


    1. aamonster
      26.11.2025 22:14

      Или через стрелочные функции.

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


      1. ermouth
        26.11.2025 22:14

        Или через стрелочные функции

        К стрелочной функции this не забайндить.

        Но новичков я бы учил…

        Опыт подсказывает, что новички связывание быстрее понимают, чем замыкания, да и синтаксически короче.

        Ну и через bind можно привязать не только this, но и любой аргумент.

        Не так, this и аргументы последовательно, не любой. С пропусками через .bind не привязать. Если нужно частичное каррирование, можно например Sugar.js .fill использовать, там можно так:

        function a(name, surname, end){return name+' '+surname+end}
        var b = a.fill(undefined, 'Doe', undefined);
        console.log(b('John','??')); // John Doe??


        1. aamonster
          26.11.2025 22:14

          К стрелочной функции this не забайндить.

          И не надо. Достаточно вместо передачи bind(...) передавать стрелочную (ну или обычную, но не использующую this) функцию-обёртку, вызывающую метод класса с нужным this.

          Если нужно частичное каррирование, можно например Sugar.js .fill использовать, там можно так:

          Ну да, но проще

          let b = (name, end) => a(name, 'Doe', end);

          ЗЫ: Вижу джаваскриптера стпрой школы, ещё с привычкой к var :-)


          1. ermouth
            26.11.2025 22:14

            Школа да, не новая ) но var тут не поэтому, в консоли он удобнее, потому что let и const с тем же именем второй раз не напишешь.


            1. aamonster
              26.11.2025 22:14

              Про школу – это больше к тому, что стаж виден по одному ключевому слову)

              А про var в консоли – почему-то не задумывался о таком применении, просто писал window.b = ... (эффект тот же).
              Забавна, кстати, разница в поведении браузеров. В консоли хрома и сафари

              {
                  let x=12
                  x
              }

              ведт себя совсем по-разному. var одинаково.


  1. cssfish
    26.11.2025 22:14

    во втором примере передача product внутрь ф-ии явно лишняя, метод же

    console.log(product.getTotalPrice(product));
    ↓
    console.log(product.getTotalPrice());
    

    а в последнем примере содержимое return в getInfo нужно в обратные кавычки заворачивать, конечно

    return ${this.name} | ${this.count} шт. | ${this.getTotalPrice()} руб.;
    ↓
    return `${this.name} | ${this.count} шт. | ${this.getTotalPrice()} руб.`;