В чем разница между статическими и нестатическими методами в классах JavaScript
Что проверяют
Понимаете ли вы, где в JavaScript живёт метод: на самом классе или на его прототипе. Для Java-разработчика вопрос с подвохом, потому что static в JS похож на джавовый, но ведёт себя иначе. Следом обычно спрашивают, чем будет this в статическом методе и наследуется ли он.
Как отвечать
Суть в том, куда попадает метод:
- обычный метод: записывается в
Example.prototype, экземпляры получают его по цепочке прототипов. Внутриthisэто экземпляр, у которого метод вызвали; - статический метод: объявляется через
staticи становится свойством самой функции-класса. Вызывается какExample.create(), у экземпляра его нет:new Example().createвернётundefined; thisв статическом методе: это класс, через который вызвали. Поэтому фабрикаstatic create() { return new this(); }в наследнике вернёт экземпляр наследника;- наследование: при
class Child extends Exampleстатика доступна какChild.create(), потому что прототипомChildстановится самExample. В Java статические методы не переопределяются, а скрываются и связываются при компиляции, в JS это обычный поиск свойства во время выполнения; - соседи по теме: статические поля, блоки инициализации
static { }и приватная статикаstatic #cacheпоявились в ES2022.
Типичные применения статики: фабрики и утилиты (Array.from(), Object.keys(), Date.now()), кеши и счётчики на уровне класса. Методам экземпляра остаётся всё, что зависит от состояния конкретного объекта.
Где спотыкаются
Утверждают, что статический метод не может работать с данными экземпляра. Может, если передать экземпляр аргументом; своего this-экземпляра у него просто нет.
Передают метод как колбэк и теряют контекст: setTimeout(obj.method) вызовет функцию без this. Со статикой то же самое: const f = Example.create; f() упадёт, если внутри используется this.
Переносят привычки из Java и ждут, что статику нельзя вызвать через наследника или что она связывается при компиляции. В JS всё решается во время выполнения по цепочке прототипов.