Как работают классы в JavaScript?
Что проверяют
Понимаете ли вы, что под классом лежат прототипы, и знаете ли современный синтаксис: приватные поля, статические блоки. Следом обычно спрашивают, куда пропадает this в методе, переданном как колбэк, и чем класс отличается от функции-конструктора.
Как отвечать
class создаёт функцию-конструктор: typeof Person вернёт "function". Методы попадают в Person.prototype и общие для всех экземпляров, а сам экземпляр связан с прототипом через [[Prototype]]. extends выстраивает цепочку: Employee.prototype наследует от Person.prototype.
Называть класс «просто сахаром» стоит с оговорками, у него есть реальные отличия от функции-конструктора:
- вызов без
new: выбрасываетTypeError; - тело класса: всегда в строгом режиме;
- объявление: не всплывает так, как функция, до строки с
classимя недоступно; - методы: неперечисляемые и не попадают в
for...in; - конструктор наследника: до вызова
super()обращение кthisдаётReferenceError.
Современные возможности: публичные поля count = 0, приватные #token с проверкой #token in obj, геттеры и сеттеры, static-методы и блоки static { } для инициализации. Наследоваться можно и от встроенных типов: class ApiError extends Error, class MyWidget extends HTMLElement для Web Components.
Для фронтенда уместно сказать, где классы живут сейчас. В React новые компоненты пишут функциями, но error boundary по-прежнему делают классом с componentDidCatch и getDerivedStateFromError. Классы остаются в Web Components, в сервисах Angular и в обёртках над SDK.
Где спотыкаются
Теряют this: const fn = user.greet; fn() получает undefined, потому что метод оторван от объекта, а код класса строгий. Помогают bind в конструкторе или поле со стрелочной функцией greet = () => {}, но тогда функция создаётся заново для каждого экземпляра и отсутствует в прототипе.
Путают private из TypeScript и #. Первое проверяется только компилятором, и в рантайме поле видно, второе закрыто на уровне языка.
Думают, что static-метод доступен у экземпляра. Он живёт на самом классе: MathUtil.add() работает, а new MathUtil().add() нет.