Типы данных в 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
Примитив (кроме null)?
typeofработает: string, number, boolean… -
2
Это null?Только
value === null— typeof соврётobject -
3
Массив?
Array.isArray(value), не typeof -
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.