Как реализовать функцию add в JavaScript, которая накапливает аргументы и возвращает сумму при вызове без аргументов
Что проверяют
Понимание замыканий: где живёт накопленное состояние, кто его удерживает и почему цепочка вызовов не теряет сумму. Заодно смотрят на аккуратность с аргументами (rest-параметры против arguments) и на то, помнит ли кандидат про финальный вызов без аргументов как условие выхода.
Как отвечать
Идея одна: функция создаёт переменную-аккумулятор и возвращает внутреннюю функцию, которая эту переменную видит по замыканию и возвращает саму себя, пока ей передают аргументы.
function add(...init) {
let sum = init.reduce((acc, n) => acc + n, 0);
const inner = (...args) => {
if (args.length === 0) return sum;
sum += args.reduce((acc, n) => acc + n, 0);
return inner;
};
return inner;
}
add(1)(2)(3)(); // 6
add(1, 2)(3)(); // 6
add()(); // 0Что важно проговорить:
- Состояние принадлежит вызову
add, а не модулю. Каждыйadd(...)создаёт новое замыкание, поэтому две независимые цепочки не мешают друг другу. Если объявитьsumснаружи, счётчик станет глобальным и второй тест сломается. - Возврат
innerизinnerсохраняет ту же лексическую область, поэтому все звенья цепочки пишут в одну и ту жеsum. args.length === 0вместоvalue === undefined. Проверка по значению ломается наadd(undefined), аargs.lengthчестно отвечает на вопрос «аргументы вообще передавали». В стрелочной функцииargumentsнедоступен, поэтому только rest-параметры.- Rest-параметры дают бесплатную поддержку
add(1, 2)(3), что интервьюер часто просит следующим шагом.
Второй вариант задачи: сумма без финальных скобок, через приведение типов.
function addLazy(...init) {
let sum = init.reduce((acc, n) => acc + n, 0);
const inner = (...args) => {
sum += args.reduce((acc, n) => acc + n, 0);
return inner;
};
inner.valueOf = () => sum;
inner.toString = () => String(sum);
return inner;
}
+addLazy(1)(2)(3); // 6
`${addLazy(1)(2)}`; // "3"Оговорка к этому варианту: console.log(addLazy(1)(2)) напечатает функцию, а не число, потому что console.log не приводит объект к примитиву. Работает только явное приведение: унарный плюс, шаблонная строка, сравнение с числом.
Где спотыкаются
Классическая ошибка: объявить sum один раз на весь модуль и не заметить, что вторая цепочка продолжает первую. Вторая по частоте: проверять «аргумент не передан» через typeof value === "undefined" и получить неверный результат на add(undefined) или на нулевом аргументе.