> Как избежать конкатенации чисел как строк в функции суммы аргументов в JavaScript? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Газпромбанк
Стек: JavaScript
> Пример ответа
Короткий ответ
Проблема возникает из-за неявного приведения типов в JavaScript: оператор + выполняет конкатенацию строк, если хотя бы один операнд - строка. Решение - явно приводить аргументы к числам перед сложением, например через Number(), унарный +, parseInt/parseFloat, или использовать reduce с начальным числовым значением. Также можно проверять типы аргументов и выбрасывать ошибку при нечисловых значениях.
Подробное объяснение
В JavaScript оператор + перегружен: для чисел он выполняет сложение, для строк - конкатенацию. Если в функцию суммы передаются аргументы разных типов, например sum(1, '2'), результат будет '12' (строка), а не 3. Это классическая проблема неявного приведения типов.
Основные подходы к решению:
- Явное приведение каждого аргумента к числу - гарантирует, что все операнды будут числами перед сложением.
- Валидация типов - проверка, что все аргументы являются числами, с выбрасыванием ошибки при несоответствии.
- Использование
BigInt- если нужна работа с большими целыми числами без потери точности. - Использование
Number.EPSILON- для корректной обработки чисел с плавающей точкой.
Важно учитывать edge cases: null приводится к 0, undefined - к NaN, строки вида ' 5 ' (с пробелами) корректно парсятся, а '5abc' даёт NaN.
На практике
В реальных проектах чаще всего используют комбинацию явного приведения и валидации. Для production-кода рекомендуется:
- Использовать
Number()или унарный+для приведения. - Добавить проверку на
NaNчерезNumber.isNaN(). - Для пользовательского ввода дополнительно применять
parseFloatс проверкой результата. - В TypeScript - использовать строгую типизацию параметров.
Пример типичной реализации в библиотеке утилит:
JAVASCRIPTfunction safeSum(...args) {return args.reduce((acc, val) => {const num = Number(val);if (Number.isNaN(num)) {throw new TypeError(`Invalid number: ${val}`);}return acc + num;}, 0);}
Пример кода
JAVASCRIPT// Проблемный вариантfunction sumBad(...args) {return args.reduce((acc, val) => acc + val, 0);}console.log(sumBad(1, '2')); // '12' - конкатенация// Решение 1: явное приведениеfunction sumWithNumber(...args) {return args.reduce((acc, val) => acc + Number(val), 0);}console.log(sumWithNumber(1, '2')); // 3// Решение 2: унарный плюсfunction sumWithUnary(...args) {return args.reduce((acc, val) => acc + +val, 0);}console.log(sumWithUnary(1, '2')); // 3// Решение 3: с валидациейfunction sumSafe(...args) {return args.reduce((acc, val) => {const num = Number(val);if (!Number.isFinite(num)) {throw new Error(`Argument "${val}" is not a finite number`);}return acc + num;}, 0);}// Решение 4: для целых чисел с BigIntfunction sumBigInt(...args) {return args.reduce((acc, val) => acc + BigInt(val), 0n);}
Как отвечать на собеседовании
Начни с чёткого описания проблемы: неявное приведение типов в операторе +. Затем перечисли основные решения, начиная с самого простого (явное приведение) и заканчивая более надёжными (с валидацией). Обязательно упомяни edge cases: null, undefined, NaN, строки с пробелами и буквами. Покажи понимание разницы между Number(), parseInt и parseFloat. Если спросят про производительность - отметь, что унарный + обычно быстрее Number(), но разница незначительна. Хорошо добавить про TypeScript как способ предотвратить проблему на этапе компиляции.
Что проверяет интервьюер
Интервьюер оценивает:
- Понимание неявного приведения типов в JavaScript.
- Знание различных способов преобразования в число и их особенностей.
- Умение обрабатывать edge cases и писать надёжный код.
- Способность выбрать подходящее решение для конкретного контекста (простота vs надёжность).
- Понимание разницы между
Number(),parseInt,parseFloatи унарным+. - Знание
Number.isNaNvs глобальнойisNaN.
Типичные ошибки
- Использование
parseIntбез указания системы счисления (radix) - может дать неожиданные результаты для строк вида'0x10'. - Забывают про
NaNкак результат приведения - нужно всегда проверять. - Путают
Number.isNaN()(не приводит к числу) с глобальнойisNaN()(приводит). - Используют
+для конкатенации строк в других частях кода, что маскирует проблему. - Не учитывают, что
nullприводится к0, аundefined- кNaN. - Применяют
parseFloatдля целых чисел, хотяparseIntточнее для этой задачи.
> Похожие задачи по frontend
Как создать и выполнить промис через конструктор в JavaScript
Как реализовать бесконечный скролл
Как реализовать функцию memo для кеширования результатов вызовов по аргументам в JavaScript
В чем разница между document.getElementsByClassName и querySelectorAll в JavaScript
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью