> Как расширять методы класса в JavaScript (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Яндекс

Стек: JavaScript

> Пример ответа

Короткий ответ

Расширение методов класса в JavaScript достигается через наследование (extends) и переопределение методов с возможностью вызова родительской реализации через super. В ES6 классах можно полностью заменить метод или расширить его, вызвав super.method() до или после добавления логики. Для статических методов используется super в статическом контексте. Альтернативно - композиция через функции высшего порядка или декораторы.

Подробное объяснение

Основной механизм - прототипное наследование, обёрнутое в синтаксис классов. При объявлении class Child extends Parent цепочка прототипов настраивается так, что экземпляры Child получают доступ к методам Parent через прототип. Переопределяя метод в Child, мы заменяем его в прототипе Child, но оригинальный метод остаётся доступен через super.method().

super работает как ссылка на прототип родителя, но с корректным контекстом this. В конструкторе super() обязателен перед this. В методах super.method() вызывает родительский метод, при этом this указывает на текущий экземпляр.

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

Более гибкий подход - композиция: обёртка метода через функцию, принимающую оригинальный метод и возвращающую новый. Это полезно для middleware, логирования, кэширования. Декораторы (stage 2) предлагают синтаксический сахар для такого расширения.

На практике

Расширение методов применяется в:

  • UI-компонентах (React, Web Components) для добавления side-эффектов к жизненному циклу
  • Сервисных классах (API-клиенты, валидаторы) для логирования, обработки ошибок
  • Паттерне Template Method, где базовый класс задаёт скелет, а наследники расширяют шаги
  • Mixin-ах через множественное наследование (Object.assign или композиция)

Важно помнить: super работает только с методами, объявленными через синтаксис метода (не стрелочные функции). Стрелочные функции в классах не имеют super и не участвуют в цепочке прототипов.

Пример кода

JAVASCRIPT
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} издаёт звук`;
}
static create(name) {
return new this(name);
}
}
class Dog extends Animal {
speak() {
// Расширяем: добавляем логирование и вызываем родительский метод
console.log(`Собака ${this.name} говорит`);
const base = super.speak();
return `${base} - Гав!`;
}
static create(name) {
// Расширяем статический метод
const instance = super.create(name);
instance.type = 'dog';
return instance;
}
}
// Композиция для расширения без наследования
function withLogging(instance, methodName) {
const original = instance[methodName];
instance[methodName] = function(...args) {
console.log(`Вызов ${methodName} с аргументами:`, args);
return original.apply(this, args);
};
return instance;
}
const dog = withLogging(new Dog('Рекс'), 'speak');
console.log(dog.speak());

Как отвечать на собеседовании

Начни с ключевого механизма - super и extends. Покажи понимание прототипной природы: super - это не родительский объект, а ссылка на прототип. Упомяни разницу между переопределением и расширением. Приведи пример с логированием или валидацией. Если спросят про альтернативы - расскажи о композиции и декораторах. Не углубляйся в детали реализации super до дополнительного вопроса.

Что проверяет интервьюер

  • Понимание прототипного наследования под капотом классов
  • Умение различать переопределение и расширение
  • Знание ограничений super (не работает со стрелочными функциями, обязателен вызов в конструкторе)
  • Осведомлённость о композиции как альтернативе наследованию
  • Практическое применение в реальных проектах (логирование, middleware)

Типичные ошибки

  • Забывают вызвать super() в конструкторе наследника - ReferenceError
  • Пытаются использовать super в стрелочных функциях - SyntaxError
  • Путают super в статических и обычных методах
  • Думают, что super ссылается на родительский экземпляр, а не на прототип
  • Переопределяют метод, но не вызывают родительский, когда это нужно для базовой функциональности
  • Используют extends для глубоких иерархий вместо композиции, создавая хрупкий код

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью