Методы в классах

Методы в классах

Технический фундамент методов и контекста

Метод класса это функция, привязанная к прототипу и вызываемая в контексте экземпляра:

  • при вызове obj.method() значение this указывает на obj;
  • при "отрыве" метода (const fn = obj.method) контекст теряется;
  • контракты методов должны сохранять инварианты объекта;
  • метод лучше либо меняет состояние, либо возвращает данные (предсказуемость API).

Эти правила помогают избегать скрытых багов со this и случайных побочных эффектов.

Почему методы это сердце класса

Класс без методов это просто контейнер для данных. Смысл ООП в том, что объект не только хранит состояние, но и умеет с ним работать. Методы описывают поведение экземпляра: изменить статус, посчитать итог, проверить условие, вернуть форматированное значение.

Ключевой момент: методы должны работать с состоянием своего экземпляра через this.

Проверь себя: почему функция calculateTotal(cart) снаружи класса и метод cart.calculateTotal() это разные уровни связности кода?

Базовый синтаксис методов

class Counter {
  constructor() {
    this.value = 0;
  }

  increment() {
    this.value += 1;
  }

  getValue() {
    return this.value;
  }
}

const counter = new Counter();
counter.increment();
console.log(counter.getValue()); // 1

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

this внутри методов

this указывает на текущий экземпляр. Если потерять контекст this, метод может работать неправильно.

class User {
  constructor(name) {
    this.name = name;
  }

  getGreeting() {
    return `Привет, ${this.name}`;
  }
}

const user = new User('Ира');
console.log(user.getGreeting());

Здесь часто путаются: если передать user.getGreeting как "голую" функцию без привязки, this может стать undefined.

setTimeout(user.getGreeting, 0); // Ошибка: потеряли this

// Вариант 1: обернуть в функцию, которая вызывает метод на объекте
setTimeout(() => console.log(user.getGreeting()), 0);

// Вариант 2: привязать контекст один раз
setTimeout(user.getGreeting.bind(user), 0);

Смотри, что важно: bind(...) создает новую функцию. Если ты вызываешь bind много раз в цикле/рендере, ты создаешь много новых функций. Обычно контекст привязывают один раз и переиспользуют.

Разделяй методы по ответственности

Методы класса лучше делить на:

  • команды (изменяют состояние): addItem, markDone;
  • запросы (возвращают данные): getTotal, isDone.

Это делает поведение предсказуемым и упрощает тесты.

class Task {
  constructor(title) {
    this.title = title;
    this.done = false;
  }

  complete() {
    this.done = true;
  }

  isCompleted() {
    return this.done;
  }
}

Реальные микро-сценарии

  1. Корзина покупок.
  • addProduct() добавляет товар;
  • removeProduct() удаляет;
  • getTotal() считает итог.
  1. Пользовательская сессия.
  • login() меняет флаг авторизации;
  • logout() очищает сессию;
  • isAuthorized() возвращает состояние.

Такой подход делает код UI проще: страница вызывает методы модели, не лезя во внутренние детали.

Частые ошибки новичков

  • Делать методы, которые меняют слишком много полей сразу без причины.
  • Возвращать из методов данные "вразнобой" без контракта.
  • Смешивать расчет и побочный эффект в одном методе.
  • Злоупотреблять статическими методами вместо экземплярных (тема дальше).
class BadCart {
  updateEverything() {
    // и считает итог, и меняет скидку, и шлет API, и пишет лог
  }
}

Дополнительный пример: безопасная передача метода как callback.

class Greeter {
  constructor(name) {
    this.name = name;
  }

  sayHi() {
    return `Hi, ${this.name}`;
  }
}

const greeter = new Greeter('Nina');
const safeCall = greeter.sayHi.bind(greeter);
console.log(safeCall());

Анти-провал: если метод трудно назвать одним глаголом, вероятно, он делает слишком много.

Что будет, если изменить входные данные

Если addProduct(price) получает отрицательное число без проверки, итог корзины становится некорректным. Значит, методы должны защищать инварианты класса, а не слепо принимать любой вход.

Проверь себя: где логичнее проверять корректность цены - в UI-слое или в методе модели?

Краткий итог

  • Методы задают поведение класса и работают через this.
  • Хорошие методы имеют четкую ответственность и понятный контракт.
  • Разделение на команды и запросы улучшает читаемость и тестируемость.
  • Контекст this и валидация входа критичны для надежного поведения.
  • Класс становится полезным, когда его методы делают работу с состоянием безопасной и предсказуемой.