Как избежать конкатенации чисел как строк в функции суммы аргументов в JavaScript?
Что проверяют
Знаете ли вы правила приведения типов в JavaScript и понимаете ли, откуда в сумме берутся строки. Следом обычно спрашивают, что функция вернёт для пустой строки, null или '12px', и почему reduce без начального значения здесь опасен.
Как отвечать
Начните с причины: если после приведения к примитиву хотя бы один операнд + оказался строкой, выполняется конкатенация, и 1 + '2' даёт '12'. Строки чаще всего приходят не из вашего кода, а из input.value, URLSearchParams или localStorage, где любое значение строка.
Каркас решения:
- rest-параметры:
function sum(...nums)вместоarguments, у которого нет методов массива, а в стрелочных функциях собственногоargumentsнет вовсе; - явное приведение:
Number(x)или унарный+xна каждом элементе, и только потом сложение; - начальное значение:
nums.reduce((acc, x) => acc + Number(x), 0). Без0аккумулятором станет первый элемент, и если это'1', дальше пойдёт склейка строк; - валидация:
Number.isFinite(n)отсекает иNaN, иInfinity. ГлобальныйisNaNсам приводит аргумент к числу и поэтому менее предсказуем.
Покажите разницу функций приведения: Number('12px') даёт NaN, а parseFloat('12px') даёт 12; Number('') и Number(null) дают 0, а Number(undefined) даёт NaN. Выбор зависит от того, что вы считаете ошибкой ввода. В TypeScript сигнатура (...nums: number[]) защитит от строк в вашем коде, но не от данных формы в рантайме.
Где спотыкаются
Пишут reduce без начального значения и не замечают, что sum('1', 2) вернёт '12'. На пустом массиве такой reduce к тому же бросит TypeError.
Молча превращают мусор в ноль. Number('') равен 0, поэтому пустое поле формы незаметно участвует в сумме, хотя правильнее показать ошибку.
Забывают про BigInt: 1n + 1 бросает TypeError, а перевод больших BigInt в Number теряет точность за пределами Number.MAX_SAFE_INTEGER. Если функция должна принимать такие значения, это нужно оговорить отдельно.