Какие типы данных существует в JavaScript?
Какие типы данных существует в JavaScript?
Теория: какие типы данных есть в JavaScript
В спецификации ECMAScript значения делятся на примитивные типы и тип object. Примитивы представляют собой неделимые значения (число, строка и т.д.), а объекты — контейнеры со свойствами и поведением.
undefined, null, boolean, number, bigint, string, symbol, object.Схема: примитивы и объекты
Значения JavaScript
├─ Примитивы (7)
│ ├─ undefined
│ ├─ null
│ ├─ boolean
│ ├─ number
│ ├─ bigint
│ ├─ string
│ └─ symbol
└─ Object (1, непримитивный)
├─ plain object {}
├─ array []
├─ function () {}
├─ date new Date()
├─ map/set new Map(), new Set()
└─ и другие встроенные/пользовательские объекты
Короткая таблица: тип, typeof, пример
| Тип | Результат typeof | Пример значения | Важная особенность |
|---|---|---|---|
undefined | undefined | undefined | “Значение отсутствует” (часто у неинициализированных переменных) |
null | object | null | Историческая особенность: typeof null возвращает object |
boolean | boolean | true | Только true и false |
number | number | 42, 3.14, NaN | Все обычные числа, включая NaN, Infinity, -0 |
bigint | bigint | 9007199254740993n | Целые числа произвольной длины, литерал с n |
string | string | "привет" | Строки в Unicode, отдельного char нет |
symbol | symbol | Symbol("id") | Уникальные идентификаторы, часто для “скрытых” ключей |
object | object (или function) | {}, [], () => {} | Объекты и функции (функции — вызываемые объекты) |
Разбор каждого типа с примерами
undefined
undefined означает, что значение не задано. Часто появляется у объявленной, но не инициализированной переменной, у отсутствующего свойства, а также как результат функции без return.
Примеры: let a; и typeof a.
let a;
console.log(a); // undefined
console.log(typeof a); // "undefined"
const obj = {};
console.log(obj.missing); // undefined
function f() {}
console.log(f()); // undefined
undefined и “не существует” — не одно и то же: переменная может не существовать (ReferenceError), а может существовать и быть равной undefined.// Пример различия (в модуле/строгом режиме будет ReferenceError)
console.log(notDeclared); // ReferenceError: notDeclared is not defined
let declared;
console.log(declared); // undefined
null
null обычно означает “пустое значение по намерению”: объект отсутствует, ссылка очищена и т.п.
Примеры: const x = null; и x === null.
const x = null;
console.log(x); // null
console.log(x === null); // true
console.log(typeof x); // "object" (историческая особенность)
Практическая проверка на “null или undefined” часто делается через x == null, потому что нестрогое равенство в этом месте намеренно устроено так, что null == undefined истинно.
const a = null;
const b = undefined;
console.log(a == null); // true
console.log(b == null); // true
console.log(a === null); // true
console.log(b === null); // false
boolean
boolean содержит только два значения: true и false. В условиях выполняется приведение к булеву значению (truthy/falsy).
Пример: Boolean("x").
console.log(typeof true); // "boolean"
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean("text")); // true
console.log(Boolean([])); // true
console.log(Boolean({})); // true
new Boolean(false) является объектом и ведет себя как truthy в условиях, что часто вызывает ошибки.const b = new Boolean(false);
console.log(typeof b); // "object"
if (b) {
console.log("Сработает, потому что это объект");
}
number
number — единственный “обычный” числовой тип: целые и дробные значения, а также специальные значения NaN, Infinity, -Infinity. В основе лежит формат IEEE 754 двойной точности, что объясняет ошибки округления.
Примеры: Number.isNaN(NaN) и 0.1 + 0.2.
console.log(typeof 123); // "number"
console.log(typeof 3.14); // "number"
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(Number.isNaN(NaN)); // true
console.log(NaN === NaN); // false
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Object.is(-0, 0)); // false (в JS существуют +0 и -0)
Для денежных расчетов часто выбирается подход “хранить в целых минимальных единицах” (например, копейки) или использовать bigint там, где нужна целочисленная точность и нет дробной части.
bigint
bigint предназначен для целых чисел произвольной длины. Литералы пишутся с суффиксом n. bigint не смешивается с number в арифметике без явного преобразования.
Примеры: 9007199254740993n и typeof 1n.
const safeLimit = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(safeLimit + 1); // 9007199254740992
console.log(safeLimit + 2); // 9007199254740992 (теряется точность)
const big = 9007199254740993n;
console.log(big + 2n); // 9007199254740995n
console.log(typeof big); // "bigint"
number и bigint выбрасывают ошибку TypeError.const a = 10n;
const b = 2;
// console.log(a + b); // TypeError: Cannot mix BigInt and other types
console.log(a + BigInt(b)); // 12n
console.log(Number(a) + b); // 12 (возможна потеря точности при больших значениях)
string
string хранит текст. Отдельного типа “символ” нет: один символ — это строка длины 1. Строки являются неизменяемыми (immutable): изменение символа “внутри” строки невозможно, создается новая строка.
Примеры: "a".length и "a"[0].
const s = "hello";
console.log(typeof s); // "string"
console.log(s.length); // 5
console.log(s[0]); // "h"
const t = "h" + "i";
console.log(t); // "hi"
length не всегда равен числу видимых символов.symbol
symbol — уникальный примитив, чаще всего применяемый как ключ свойства, чтобы избежать конфликтов имен. Символы уникальны даже при одинаковом описании.
Примеры: Symbol("id") и sym1 === sym2.
const sym1 = Symbol("id");
const sym2 = Symbol("id");
console.log(typeof sym1); // "symbol"
console.log(sym1 === sym2); // false
const user = {
name: "Ann",
[sym1]: 123
};
console.log(user.name); // "Ann"
console.log(user[sym1]); // 123
console.log(Object.keys(user)); // ["name"] (символьный ключ не перечисляется через keys)
Существует глобальный реестр символов через Symbol.for("key"), в котором одинаковый ключ возвращает один и тот же символ.
const a = Symbol.for("shared");
const b = Symbol.for("shared");
console.log(a === b); // true
object
object — непримитивный тип: значения имеют идентичность (ссылку), свойства и прототип. Сюда относятся обычные объекты, массивы, функции, даты, коллекции и пользовательские экземпляры классов.
Примеры: typeof {} и Array.isArray([]).
const obj = { a: 1 };
const arr = [1, 2, 3];
function fn() {}
console.log(typeof obj); // "object"
console.log(typeof arr); // "object"
console.log(typeof fn); // "function"
console.log(Array.isArray(arr)); // true
console.log(arr instanceof Array); // true
Ключевая особенность объектов — сравнение по ссылке, а не по содержимому.
const a = { x: 1 };
const b = { x: 1 };
const c = a;
console.log(a === b); // false (разные объекты)
console.log(a === c); // true (одна и та же ссылка)
Важные проверки типов на практике
Оператор typeof полезен, но имеет нюансы. Для надежных проверок обычно комбинируются разные техники.
// typeof для примитивов
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (нюанс)
console.log(typeof true); // "boolean"
console.log(typeof 1); // "number"
console.log(typeof 1n); // "bigint"
console.log(typeof "x"); // "string"
console.log(typeof Symbol()); // "symbol"
// typeof для объектов
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof (() => {})); // "function"
Для различения “обычный объект vs массив vs дата” часто применяются:
Array.isArray(value)для массивовvalue instanceof Dateдля дат (в рамках одного глобального контекста)Object.prototype.toString.call(value)как более универсальный способ
function tagOf(v) {
return Object.prototype.toString.call(v);
}
console.log(tagOf([])); // "[object Array]"
console.log(tagOf({})); // "[object Object]"
console.log(tagOf(new Date())); // "[object Date]"
console.log(tagOf(null)); // "[object Null]"
console.log(tagOf(undefined)); // "[object Undefined]"
Примитивы vs объекты: копирование и изменение
Примитивные значения копируются “как значение”, а объекты передаются как ссылка на один и тот же объект. Это особенно важно при присваивании и передаче в функции.
// Примитив: копия значения
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
// Объект: копия ссылки
let o1 = { count: 1 };
let o2 = o1;
o2.count = 2;
console.log(o1.count); // 2
console.log(o2.count); // 2
Чтобы получить “поверхностную” копию объекта, часто используется structuredClone (глубокая копия, где поддерживается) или комбинации вроде Object.assign/spread для поверхностной копии.
const original = { inner: { x: 1 } };
const shallow = { ...original };
shallow.inner.x = 999;
console.log(original.inner.x); // 999 (вложенный объект общий)
Частые ошибки начинающих
- Ожидание, что
nullдастtypeof null === "null", хотя фактически возвращается"object" - Попытка хранить “большие целые” в
numberбез потери точности, хотя безопасный диапазон ограниченNumber.MAX_SAFE_INTEGER - Смешивание
bigintиnumberв арифметике без преобразования - Ожидание, что массив — отдельный тип, хотя он является объектом и проверяется через
Array.isArray - Использование объектов-оберток
new Number(1),new String("x"),new Boolean(false)вместо примитивов
Кратко: В JavaScript существует 8 типов данных: 7 примитивов (undefined, null, boolean, number, bigint, string, symbol) и 1 непримитивный (object). Массивы и функции относятся к object (функции имеют typeof === "function"), а typeof null — историческое исключение, возвращающее "object".