Типы данных в JavaScript: примитивы и объекты

Содержание

О проверке кода. Примеры не запускались — в отличие от материалов по Node.js с фактическим выводом. Говорим прямо, а не ставим бейдж «проверено».

Типы — фундамент, на котором держатся все ловушки JavaScript. Понять их деление на примитивы и объекты — значит перестать удивляться странностям вроде '5' + 3.

Восемь типов

JavaScript делит всё на примитивы и объекты.

Семь примитивов:

Тип Пример Зачем
string 'привет' текст
number 42, 3.14 числа (целые и дробные вместе)
boolean true, false логика
undefined undefined значение не задано
null null намеренное «пусто»
symbol Symbol('id') уникальные ключи
bigint 9007199254740993n очень большие целые

Восьмой тип — object: всё остальное. И вот ключевой момент, который снимает половину путаницы: массивы, функции, даты, регулярки — это всё объекты, просто разновидности.

Примитив против объекта

Разница не в синтаксисе, а в поведении при копировании:

// примитив копируется ПО ЗНАЧЕНИЮ
let a = 5;
let b = a;
b = 10;
console.log(a);   // 5 — a не изменилась

// объект копируется ПО ССЫЛКЕ
let obj1 = { x: 5 };
let obj2 = obj1;
obj2.x = 10;
console.log(obj1.x);   // 10 — тот же объект!

Примитивы копируются по значению — каждая переменная своя. Объекты копируются по ссылке — переменные указывают на один объект. Это отдельная важная тема, из которой растёт множество багов «я поменял копию, а изменился оригинал».

Проверка типа: typeof и его ловушки

typeof 'привет';    // "string"
typeof 42;          // "number"
typeof true;        // "boolean"
typeof undefined;   // "undefined"
typeof function(){}; // "function"

typeof null;        // "object" ← ОШИБКА!
typeof [1, 2, 3];   // "object" ← массив тоже объект

Две ловушки, о которые спотыкаются все:

typeof null возвращает 'object' — это баг из первой версии языка 1995 года. Его не стали чинить, чтобы не сломать код, который на него уже полагался. Формально null — отдельный примитив, но typeof про него врёт. Поэтому null проверяют напрямую:

value === null;   // единственный надёжный способ

typeof не отличает массив от объекта — для обоих 'object'. Массив проверяют специально:

Array.isArray([1, 2, 3]);   // true
Array.isArray({ x: 1 });    // false
Как надёжно определить тип
  1. 1 Примитив (кроме null)?typeof работает: string, number, boolean…
  2. 2 Это null?Только value === null — typeof соврёт object
  3. 3 Массив?Array.isArray(value), не typeof
  4. 4 Конкретный объект?value instanceof Date, value instanceof RegExp

null против undefined

Оба означают «нет значения», но по-разному:

let x;              // undefined — объявлена, но ничего не присвоено
let y = null;       // null — вы намеренно поставили «пусто»

function find() {}  // ничего не вернула → undefined

undefined — «значение не задано», обычно от языка: необъявленное свойство, функция без return, пропущенный аргумент. null — намеренное «здесь пусто», от разработчика: вы сами ставите его, чтобы сказать «значения нет и это ожидаемо».

Практика: возвращайте null, когда «не нашлось» — это осознанный ответ. undefined оставьте языку.

Приведение типов: источник багов

JavaScript охотно превращает типы друг в друга автоматически, и это коварно:

'5' + 3;        // "53" — число стало строкой (склейка)
'5' - 3;        // 2   — строка стала числом (вычитание)
5 + true;       // 6   — true стало 1
'' == false;    // true — оба привелись к чему-то общему
[] == false;    // true — массив тоже привёлся

Плюс со строкой означает склейку, поэтому '5' + 3 даёт '53', а минус — арифметику. Эти правила запомнить невозможно, поэтому есть простое спасение:

Сравнивайте через ===, а не ==. Тройное равенство не приводит типы: '5' === 5 это false, как и ожидается. Двойное == запускает приведение и даёт результаты, которые невозможно предсказать. Про операторы подробнее — в отдельной статье.

Числа: одна ловушка

number в JavaScript — это дробные числа с плавающей точкой, даже когда выглядят целыми. Отсюда знаменитое:

0.1 + 0.2;              // 0.30000000000000004, а не 0.3
0.1 + 0.2 === 0.3;      // false!

Это не баг JavaScript, а свойство двоичной арифметики во всех языках. Про числа и точность — отдельно; пока запомните: деньги не хранят в дробных числах, а сравнивают их с допуском, а не через ===.


Смежные темы: примитивы и ссылки — копирование; операторы — приведение и сравнение; переменные. Полный список — в уроках JavaScript.

Частые вопросы

Сколько типов данных в JavaScript?
Восемь: семь примитивов (string, number, boolean, null, undefined, symbol, bigint) и объект. Массивы, функции, даты — это всё объекты, просто разного вида.
Почему typeof null возвращает object?
Это ошибка из первой версии языка 1995 года, которую не стали исправлять, чтобы не сломать существующий код. Формально null — это отдельный примитив, но typeof для него врёт. Проверяют null сравнением: value === null.
Чем null отличается от undefined?
undefined — значение не задано (переменная объявлена, но ничего не присвоено). null — намеренное «пусто», которое вы ставите сами. undefined обычно от языка, null от разработчика.
Как отличить массив от объекта?
typeof и для массива, и для объекта вернёт object. Массив проверяют через Array.isArray(value) — это единственный надёжный способ.
Что такое приведение типов?
Автоматическое превращение одного типа в другой: строка + число даёт строку, а число в условии становится булевым. Это источник багов вроде ‘5’ + 3 === ‘53’. Поэтому сравнивают через === без приведения.