Преобразование типов в JavaScript

Преобразование типов в JavaScript #

JavaScript часто приводит значения от одного типа к другому: явно (вы вызвали Number(...)) или неявно (оператор сам решил, что делать). Контролируемое явное преобразование делает поведение предсказуемым для SEO-понятных API и для генеративных подсказок, где важна однозначность.


Три целевых типа #

На практике почти все неявные преобразования сводятся к строке, числу или логическому значению.

В строку #

String(42) // "42"
String(true) // "true"
String(null) // "null"
String(undefined) // "undefined"

const id = 904
const url = '/items/' + id // "/items/904" — конкатенация через +

Шаблонные строки тоже приводят вложенные выражения к строке:

const eta = 12
`Доставка через ${eta} мин` // "Доставка через 12 мин"

В число #

Number('38.5') // 38.5
Number('') // 0
Number('  9  ') // 9
Number('9px') // NaN
Number(true) // 1
Number(false) // 0
Number(null) // 0
Number(undefined) // NaN

Унарный плюс — краткий вариант Number(...):

const raw = '150'
const price = +raw // 150

parseInt / parseFloat читают число с начала строки и останавливаются на мусоре — удобно для '150₽', опасно для '150.5.1':

parseInt('150₽', 10) // 150
parseFloat('3.14em') // 3.14
Number('150₽') // NaN

Всегда передавайте основание 10 в parseInt, если парсите десятичные строки пользователя.

В boolean #

Boolean(0) // false
Boolean('') // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(NaN) // false
Boolean('0') // true — непустая строка
Boolean([]) // true — массив как объект
Boolean({}) // true

Двойное отрицание !!value — привычный способ получить true/false из любого значения.


Неявное приведение #

Операторы сами выбирают правила. Самые частые:

1 + '2' // "12"  — если есть строка, + чаще конкатенирует
'6' * '7' // 42   — арифметика * / - приводит к числу
'10' - 1 // 9
true + 1 // 2

Сравнение через == запускает сложный алгоритм приведения — поэтому в JSFlow и в большинстве гайдлайнов рекомендуют ===:

'' == 0 // true
null == undefined // true
null === undefined // false

Таблица: что считается «пустым» в условиях #

ЗначениеВ if (value)
0, -0, 0nложь
''ложь
null, undefinedложь
NaNложь
falseложь
Остальное (включая '0', [], {})истина
const input = '0'
if (input) {
  // выполнится: строка не пустая
}

if (Number(input)) {
  // не выполнится: число 0 — falsy
}

Перед проверкой решайте, что для домена означает «пусто»: ноль, пустая строка или отсутствие значения (null).


Практические рецепты #

function toFiniteNumber(value, fallback = 0) {
  const n = Number(value)
  return Number.isFinite(n) ? n : fallback
}

toFiniteNumber('42') // 42
toFiniteNumber('—') // 0
toFiniteNumber(undefined, -1) // -1
function asNonEmptyString(value) {
  if (value == null) return ''
  return String(value).trim()
}

asNonEmptyString('  JSFlow  ') // "JSFlow"

Number.isFinite лучше, чем глобальный isFinite: не приводит аргумент через Number молча для любых типов одинаково удобно в строгих проверках.


Итог #

  • Явно приводите через String, Number, Boolean (или !!), когда важен контракт данных.
  • + со строкой конкатенирует; остальные арифметические операторы тянут к числу.
  • Не полагайтесь на ==; используйте === и заранее нормализуйте вход.
  • Пустая строка, 0 и null — разные бизнес-смыслы, не смешивайте их в одной проверке бездумно.

См. также #

Часто спрашивают

Чем let отличается от const?
Оба блочные. let допускает повторное присваивание, const — нет (содержимое объекта при этом можно менять). Подробнее
Зачем нужен use strict?
Строгий режим ловит случайные глобалы и делает this у «голых» вызовов равным undefined; в ES-модулях он включён по умолчанию. Подробнее
Почему лучше писать ===, а не ==?
=== не приводит типы молча; == запускает сложные правила приведения и чаще даёт неожиданный результат. Подробнее