Как реализовать метод reset для функции с ограничением вызовов через замыкания
Что проверяют
Понимаете ли вы, что замыкание хранит состояние между вызовами и что функция в JavaScript это объект, к которому можно прицепить метод. Следом обычно спрашивают, что возвращать после исчерпания лимита и как это типизировать в TypeScript.
Как отвечать
Каркас такой: фабрика limit(fn, n) заводит в замыкании let calls = 0 и let lastResult, возвращает обёртку и вешает на неё reset.
- обёртка: объявляется через
function, а не стрелкой, и вызываетfn.apply(this, args). Так сохраняются и аргументы, и контекст, если обёртку назначат методом объекта; - проверка лимита: если
calls < n, увеличиваем счётчик, вызываемfnи запоминаем результат. Иначе возвращаемlastResult, как это делают_.onceи_.beforeв lodash, илиundefined, если так договорились; - порядок инкремента: счётчик растёт до вызова
fn. Еслиfnрекурсивно вызовет обёртку или бросит исключение, лимит всё равно не будет превышен; - сброс:
wrapper.reset = () => { calls = 0; lastResult = undefined; }. Стрелка здесь уместна: ей нужен доступ к переменным замыкания, а не кthis.
Возвращать объект { call, reset } тоже рабочий вариант, но он меняет интерфейс: вызывающий код пишет limited.call() вместо limited(), и обёртку уже нельзя передать туда, где ждут обычную функцию. Метод на самой функции сохраняет совместимость. В TypeScript тип описывается пересечением: ((...args: Parameters<F>) => ReturnType<F> | undefined) & { reset(): void }.
Каждый вызов фабрики создаёт своё замыкание, поэтому reset одной обёртки не трогает счётчики других. Это стоит проговорить, если спросят про несколько экземпляров.
Где спотыкаются
Выносят счётчик в переменную модуля. Тогда все ограниченные функции делят один лимит, а reset у одной сбрасывает всех.
Теряют аргументы и результат. Обёртка вида () => { fn(); } проходит пример из условия, но ломается на первом реальном вызове с параметрами.
Путают семантику _.before(n, fn). Эта функция вызывает fn, пока число вызовов меньше n, то есть не больше n - 1 раз. Если сослаться на неё как на готовый аналог лимита n, интервьюер поймает на ошибке на единицу.