Какие типы данных есть в JavaScript?
Вопрос
Какие типы данных существуют в JavaScript, чем примитивы отличаются от объектов, и почему typeof null возвращает 'object'?
Короткий ответ
В JavaScript семь примитивных типов — string, number, boolean, null, undefined, symbol, bigint — и один составной тип, object (к нему относятся массивы, функции, даты и т.д.). Примитивы неизменяемы и хранятся по значению, объекты хранятся по ссылке. typeof null === 'object' — это исторический баг движка, а не логичное поведение.
Подробный ответ
Примитивы копируются при присваивании и сравнении: каждая переменная хранит собственную независимую копию значения.
string— строки, неизменяемы (любая "модификация" создаёт новую строку).number— числа с плавающей точкой (IEEE 754), включаяNaNиInfinity.boolean—true/false.null— намеренное отсутствие значения, устанавливается явно.undefined— переменная объявлена, но значение не присвоено.symbol(ES6) — уникальный, неизменяемый идентификатор, часто используется как "скрытый" ключ объекта.bigint(ES2020) — числа произвольной точности для значений за пределамиNumber.MAX_SAFE_INTEGER.
Объекты — единственный составной тип. Переменная хранит не сам объект, а ссылку на область памяти (heap), поэтому при копировании переменной копируется ссылка, а не содержимое. Массивы, функции, Map, Set, Date — всё это объекты под капотом.
Важное отличие для сравнения: примитивы сравниваются по значению (1 === 1 → true), объекты — по ссылке ({} === {} → false, даже если содержимое идентично).
Про typeof null === 'object': в первой версии JS каждое значение представлялось как тип-тег + значение. Тег 000 означал объект, а null кодировался как нулевой указатель (0x00), поэтому получал тот же тег. Это признанная ошибка в спецификации, которую не исправили из соображений обратной совместимости — слишком много кода в вебе уже зависело от такого поведения.
Ещё одна практическая деталь — typeof function(){} возвращает 'function', хотя функции технически являются объектами; это единственное исключение, добавленное для удобства.
Пример
// Примитивы копируются по значению
let a = 10
let b = a
b = 20
console.log(a, b) // 10 20 — независимые копии
// Объекты хранятся по ссылке
const obj1 = { count: 1 }
const obj2 = obj1
obj2.count = 2
console.log(obj1.count) // 2 — это один и тот же объект в памяти
// typeof для разных типов
console.log(typeof 'hi') // "string"
console.log(typeof 42) // "number"
console.log(typeof true) // "boolean"
console.log(typeof undefined) // "undefined"
console.log(typeof Symbol()) // "symbol"
console.log(typeof 10n) // "bigint"
console.log(typeof {}) // "object"
console.log(typeof []) // "object" — массив тоже объект
console.log(typeof null) // "object" — исторический баг!
console.log(typeof function(){}) // "function" — особый случай
// Надёжная проверка на null
const value = null
console.log(value === null) // true
Дополнительные вопросы
- Чем отличается сравнение через
===отObject.is()на примерахNaNи-0? - Как проверить, что переменная — именно массив, а не просто объект (
Array.isArray)? - Что такое boxing примитивов и зачем у строк есть методы, если строка — не объект?