Какие типы данных есть в JavaScript?

JuniorJavaScript #javascript #basics

Вопрос

Какие типы данных существуют в 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 примитивов и зачем у строк есть методы, если строка — не объект?