typeof в JavaScript: что возвращает оператор для каждого типа данных

Ноутбук с редактором кода и консолью на столе разработчика Программирование и разработка

Оператор typeof в JavaScript возвращает строку с названием типа значения: "number", "string", "boolean", "undefined", "bigint", "symbol", "object" или "function". Для чисел, строк и других примитивов результат точный, а null, массив и дата одинаково дают "object", и в этих случаях нужна другая проверка.

Все примеры запускались в Node.js 24.14. Результаты typeof задаёт спецификация ECMAScript, поэтому в браузере они те же.

Ноутбук с редактором кода и консолью на столе разработчика

Синтаксис оператора typeof

Пишется слово typeof, пробел и операнд: переменная, литерал или выражение. Скобки допустимы, но это обычная группировка, а не вызов функции, поэтому typeof(5) и typeof 5 работают одинаково:

console.log(typeof 5, typeof(5), typeof typeof 5); // number number string

Третий результат показывает, что typeof всегда возвращает строку. Значит, сравнивать его нужно со строкой в кавычках и в нижнем регистре: typeof x === "number".

Восемь типов данных в JavaScript и результат typeof

В спецификации JavaScript восемь типов: семь примитивных (undefined, null, boolean, number, bigint, string, symbol) и object. Сам примитив изменить нельзя, переменной можно только присвоить другое значение, а объект хранит набор свойств. Вот что typeof возвращает для каждого:

console.log(typeof undefined);       // undefined
console.log(typeof null);            // object
console.log(typeof true);            // boolean
console.log(typeof 42);              // number
console.log(typeof 10n);             // bigint
console.log(typeof "hello");         // string
console.log(typeof Symbol("id"));    // symbol
console.log(typeof { name: "Аня" }); // object
console.log(typeof function () {});  // function

Строк девять, а разных результатов восемь: null и объект дают одинаковый "object", а функции получили свою строку.

Тип данных Пример значения Что возвращает typeof
Undefined undefined "undefined"
Null null "object"
Boolean (логический) true, false "boolean"
Number (числовой) 42, 3.14, NaN, Infinity "number"
BigInt 10n "bigint"
String "hello", пустая строка "" "string"
Symbol Symbol("id") "symbol"
Object: функция или класс function () {}, class A {} "function"
Object: всё остальное {}, [], new Date(), /abc/ "object"

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

Восемь ячеек органайзера с разными деталями: восемь типов данных JavaScript

Почему typeof null возвращает object

В первой версии JavaScript значение хранилось вместе с меткой типа. У объектов метка была 0, а null представлял нулевой указатель, у которого метка тоже получилась 0. Отсюда typeof null возвращает "object". Исправление на typeof null === "null" для спецификации ECMAScript предлагали, но предложение отклонили.

Читайте также:  ModuleNotFoundError: No module named в Python: причины и как исправить

Проверяйте null строгим сравнением. Если нужен любой объект, кроме null, отсеките его первым условием. Массив, Date и Map такую проверку тоже пройдут:

const user = null;
console.log(typeof user === "object", user !== null && typeof user === "object");
// true false

Массивы, даты и встроенные объекты

Массив, дата, регулярное выражение и встроенный объект Math для typeof одинаковы, а метод Math.max уже функция:

console.log(typeof [1, 2, 3], typeof new Date(), typeof /abc/, typeof Math);
// object object object object
console.log(Array.isArray([1, 2, 3]), typeof Math.max);
// true function

Массив проверяют через Array.isArray(). Для дат и своих классов подходит instanceof: он смотрит цепочку прототипов, поэтому массив для него одновременно Array и Object, а null instanceof Object даёт false.

typeof function, классы и async-функции

Класс для typeof тоже функция, как и async-функция, хотя её вызов возвращает промис:

async function load() { return 1; }
console.log(typeof class User {}, typeof load, typeof load());
// function function object

Проверка typeof callback === "function" перед вызовом защищает от TypeError: callback is not a function, если в параметр передали что-то другое.

typeof NaN: «не число» с типом number

NaN получается, когда арифметика не может дать число. По типу он всё равно остаётся числом, и typeof возвращает "number":

const n = Number("12px");
console.log(n, typeof n);                                        // NaN number
console.log(Number.isNaN(n), isNaN("abc"), Number.isNaN("abc")); // true true false

NaN не равен даже себе, поэтому n === NaN всегда false. Глобальная isNaN() сначала превращает аргумент в число, и строка "abc" у неё тоже считается NaN. Number.isNaN() ничего не преобразует, лучше использовать её. Если нужно обычное конечное число, проверка выглядит так: typeof x === "number" && Number.isFinite(x).

Необъявленная переменная и временная мёртвая зона

typeof для имени, которое нигде не объявлено, возвращает "undefined" без ошибки. Переменная let или const до строки объявления ведёт себя иначе:

console.log(typeof notDeclared);   // undefined
try {
  console.log(typeof price);
  let price = 100;
} catch (error) {
  console.log(error.name + ": " + error.message);
}
// ReferenceError: Cannot access 'price' before initialization

Это временная мёртвая зона: до строки let price имя уже занято, но значения ещё нет. Подробно она разобрана в статье про let и const в JavaScript. Проверка необъявленного имени иногда нужна, если один код запускается и в браузере, и в Node.js:

console.log(typeof window, typeof process); // undefined object
const isBrowser = typeof window !== "undefined";

В Node.js window нет, и обращение window.location без такой проверки упало бы с ReferenceError: window is not defined.

Ноутбук с браузером и небольшой сервер на одном столе: один код в браузере и в Node.js

Обёртки new String, new Number и new Boolean

Когда у строки вызывают метод, JavaScript на время оборачивает её в объект String. Вручную через new такие обёртки не создают: строгое сравнение со строкой даёт false, а new Boolean(false) в условии истинен.

const a = "text";
const b = new String("text");
console.log(typeof a, typeof b, a === "text", b === "text"); // string object true false

const flag = new Boolean(false);
if (flag) console.log("условие выполнилось, хотя внутри false");
// условие выполнилось, хотя внутри false

Любой объект в условии истинен, даже обёртка над false. Без new те же функции работают как преобразование и возвращают примитив: typeof String(42) даёт "string", typeof Number("42") даёт "number".

Преобразование типов и данные извне

Значение из поля формы, из командной строки или из JSON, например возраст, часто приходит строкой, хотя выглядит как число:

const data = JSON.parse('{"name": "Аня", "age": "25", "score": 7, "phone": null}');
for (const key in data) console.log(key, typeof data[key]);
// name string
// age string
// score number
// phone object
console.log(typeof process.argv[2]); // string (запуск: node app.js 42)

Свойства здесь перебирает цикл for...in. Как устроены циклы, разобрано в статье про циклы while, for и do while.

Читайте также:  Рекурсия C++: как работает, примеры и когда лучше цикл

Оператор * превращает строку в число сам, а + склеивает строки:

console.log("5" * 2, "5" + 2, "5" == 5, "5" === 5); // 10 52 true false
console.log(typeof ("5" * 2), typeof ("5" + 2));    // number string

Нестрогое == приводит типы перед сравнением, строгое === сравнивает и тип, и значение. Мы советуем привести ввод к числу явно через Number() и проверить typeof и Number.isFinite() до вычислений, тогда «52» вместо 7 в сумме не появится.

Разработчик проверяет в консоли, какие данные пришли из формы

Функция, чтобы определить тип точнее

Когда нужно отличить null, массив, дату и структуры вроде Map, удобна своя функция. Метод Object.prototype.toString возвращает строку вида [object Date], из неё вырезаем имя:

function getType(value) {
  if (value === null) return "null";
  if (Array.isArray(value)) return "array";
  const type = typeof value;
  if (type !== "object") return type;
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

const values = [null, [], new Date(), /x/, {}, new Map(), 5, () => 1];
console.log(values.map(getType).join(" "));
// null array date regexp object map number function

Сам typeof полезен для примитивов и функций, и для них getType() отдаёт его результат как есть. Объект своего класса функция назовёт object, в такой ситуации нужен instanceof.

Частые ошибки с typeof

Сравнение с undefined без кавычек

typeof возвращает строку, а undefined без кавычек это значение, поэтому условие никогда не выполнится:

let value;
console.log(typeof value === undefined);   // false
console.log(typeof value === "undefined"); // true
console.log(typeof 5 === "Number");        // false

Третья строка показывает ошибку в регистре: "Number" с большой буквы не совпадёт ни с одним результатом.

Забытые скобки вокруг выражения

У typeof приоритет выше, чем у сложения, поэтому он выполняется первым:

const age = 30;
console.log(typeof age + 1, typeof (age + "1")); // number1 string

Первое выражение взяло тип age и приклеило к нему единицу. Чтобы узнать тип результата, выражение берут в скобки.

Читайте также:  "Почему обучение программированию требует усилий — ключевые трудности и полезные советы для новичков"

Редактор кода с подсвеченной строкой, где ошибка в проверке типа

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

Чем typeof отличается от instanceof?

typeof возвращает строку с названием типа и работает с любым значением, включая необъявленные имена (но не let и const до объявления). Оператор instanceof возвращает true или false и проверяет, есть ли прототип конструктора в цепочке объекта; для примитивов он даёт false.

Работает ли typeof с BigInt и Symbol?

Да, для них есть свои строки: typeof 10n даёт "bigint", typeof Symbol("id") даёт "symbol". Тип bigint поддерживают все браузеры с сентября 2020 года. Смешать его с обычным числом нельзя: 10n + 1 падает с TypeError: Cannot mix BigInt and other types, use explicit conversions.

Как проверить, что переменная строка?

Для простой проверки хватает typeof x === "string". Строка, созданная через new String(), её не пройдёт, но обычно такие обёртки в коде не встречаются.

Что вернёт typeof для undefined?

Строку "undefined". Так же отвечает оператор для переменной let без значения, для отсутствующего свойства объекта (typeof user.email) и для необъявленного имени.

Оцените статью
bestprogrammer.ru
Добавить комментарий