Первая статья из серии, в которой мы разбираем ключевые темы JavaScript, необходимые для успешного прохождения технического интервью. Сегодня говорим о фундаменте — типах данных.
Введение
Когда вы идёте на собеседование по JavaScript, даже если позиция подразумевает работу с Node.js или фреймворками, интервьюер почти всегда начинает с основ. И одна из первых тем — типы данных. Почему? Потому что непонимание разницы между примитивами и объектами, особенностей преобразования и проверки типов приводит к трудноуловимым багам. А ещё это отличный способ проверить, насколько глубоко кандидат понимает язык.
В этой статье мы разберём:
- Примитивные и ссылочные типы — в чём разница.
- Как происходит преобразование типов (явное и неявное).
- Чем отличается === от == и почему лучше всегда использовать строгое равенство.
- Какие значения считаются «ложными» (falsy).
- Как правильно проверить тип переменной.
Материал рассчитан на начинающих разработчиков и тех, кто хочет систематизировать знания перед интервью. Поехали!
1. Примитивы и объекты: в чём принципиальная разница?
В JavaScript все данные делятся на две группы: примитивные (простые значения) и ссылочные (объекты).
Примитивные типы (их семь)
- number — числа (целые, дробные, Infinity, NaN)
- string — строки
- boolean — true / false
- undefined — значение не присвоено
- null — «ничего», пусто
- symbol (ES6) — уникальный идентификатор
- bigint (ES2020) — целые числа произвольной длины
Примитивы неизменяемы. Вы не можете изменить, например, символ строки по индексу — операция вернёт новую строку, но исходная останется прежней.
Ссылочные типы
Всё, что не является примитивом, — это объект. Сюда входят:
- обычные объекты {}
- массивы []
- функции
- даты new Date()
- регулярные выражения /regex/
- и многое другое
Главное отличие: примитивы хранятся и передаются «по значению», а объекты — «по ссылке».
Рассмотрим на примере:
Когда вы присваиваете примитив новой переменной, создаётся независимая копия значения. С объектами копируется только ссылка на область памяти, поэтому обе переменные смотрят на один и тот же объект.
Упаковка примитивов (autoboxing)
Вы когда-нибудь задумывались, почему у примитивов есть методы? Например, 'hello'.toUpperCase(). Ведь строка — примитив, у которого не может быть свойств. Дело в том, что в момент вызова метода JavaScript временно оборачивает примитив в объект-обёртку (String, Number, Boolean), вызывает метод, а затем уничтожает эту обёртку. Это называется autoboxing.
Специально создавать обёртки через new String('hello') не рекомендуется — это приводит к путанице с типами и может вызвать неожиданное поведение.
2. Преобразование типов (type coercion)
JavaScript — язык с динамической типизацией, поэтому значения могут автоматически преобразовываться в зависимости от контекста. Это удобно, но часто становится причиной неочевидных ошибок.
Явное преобразование
Мы сами указываем, во что хотим превратить значение:
- В строку: String(value) или value.toString() (но последнее не сработает для null и undefined).
- В число: Number(value), parseInt(value, radix), parseFloat(value).
- В булево: Boolean(value) или двойное отрицание !!value.
Примеры:
Неявное преобразование
Автоматически происходит:
- В арифметических операциях (+, -, *, /, %).
- При сравнениях (==, >, <, >=, <=).
- В логических контекстах (if, while, &&, ||, !).
Правила преобразования
1. Строковое: если в операции + один из операндов строка, второй тоже преобразуется в строку.
2. Численное: для операций -, *, /, %, унарного +, а также для сравнений (>, < и т.д.) значения преобразуются в числа.
При этом:
- true → 1, false → 0
- null → 0
- undefined → NaN
- Строка, не являющаяся числом, → NaN
3. Логическое: в условиях все значения приводятся к true или false.
Falsy значения (приводятся к false):
- false
- 0, -0
- 0n (bigint ноль)
- '' (пустая строка)
- null
- undefined
- NaN
- document.all (редкость)
Все остальные значения — truthy, включая пустые объекты {}, пустые массивы [], даже строку 'false'.
3. Строгое и нестрогое равенство: === vs ==
- === — строгое равенство. Сравнивает значения без преобразования типов. Если типы разные — сразу false.
- == — нестрогое равенство. При необходимости преобразует типы по описанным выше правилам.
Примеры:
Правила == достаточно сложны и могут привести к неожиданностям, поэтому практически всегда рекомендуется использовать === (и !==). Исключение — когда вы намеренно хотите допустить преобразование, но такие случаи редки и обычно лучше сделать явное приведение.
4. Проверка типа
В JavaScript есть несколько способов узнать тип значения. Рассмотрим каждый.
typeof – оператор
Возвращает строку с типом операнда.
Плюсы: быстрый, работает для большинства примитивов.
Минусы: null определяется как "object" (это признано багом, но исправлять его не стали ради обратной совместимости). Массивы тоже "object", поэтому для детальной проверки объектов нужны другие методы.
instanceof – проверка принадлежности классу
Проверяет, есть ли конструктор в цепочке прототипов объекта.
Минусы:
- Не работает с примитивами (кроме случаев, когда они созданы через конструктор, например new Number(5), но так обычно не пишут).
- Может дать неверный результат при работе с iframe (разные глобальные объекты).
Array.isArray() – проверка на массив
Специальный метод, который надёжно определяет, является ли значение массивом.
Number.isNaN() – проверка на NaN
Глобальная isNaN() сначала преобразует аргумент в число, поэтому isNaN('строка') вернёт true. Number.isNaN() проверяет строго: значение должно быть именно NaN.
Object.prototype.toString.call(value) – универсальный способ
Возвращает внутренний тег объекта в формате "[object Type]". Надёжно работает для любых значений.
Этот метод часто используют в библиотеках для создания точных определителей типа, так как он различает даже null и undefined.
Заключение
Мы разобрали фундаментальную тему — типы данных в JavaScript. Теперь вы знаете:
- чем примитивы отличаются от объектов;
- как и когда происходит преобразование типов;
- почему === безопаснее ==;
- какие значения считаются falsy;
- как правильно проверить тип переменной.
Эти знания не раз помогут вам избежать скрытых ошибок и уверенно отвечать на собеседовании. В следующей статье серии «JavaScript: подготовка к собеседованию» мы перейдём к функциям и контексту — разберём объявление функций, параметры, замыкания и ключевое слово this.
Подписывайтесь, чтобы не пропустить!
Вопросы для самопроверки:
- Какие типы данных в JavaScript являются примитивными?
- Что произойдёт, если сравнить null == undefined и null === undefined?
- Какие значения приводятся к false в логическом контексте?
- Почему typeof null возвращает "object"?
- Как надёжно проверить, является ли переменная массивом?