typeof и необъявленная переменная в JavaScript

Что будет, если вызвать typeof на необъявленной переменной?

Теория по задаче

Оператор typeof является унарным оператором JavaScript, который возвращает строку с типом значения. Особенность typeof состоит в том, что он умеет безопасно обрабатывать обращение к идентификатору, которого не существует в текущей области видимости: вместо выброса исключения возвращается строка undefined.

Строка undefined — это результат typeof, а не само значение переменной; то есть возвращается именно текст undefined.

Почему ошибки нет: ключевая особенность typeof

В обычном выражении обращение к необъявленной переменной вызывает ReferenceError, потому что движок пытается получить значение по имени, но не находит привязку (binding) в окружениях выполнения.

У typeof сделано исключение: при проверке идентификатора, который невозможно разрешить (unresolvable reference), результатом становится строка undefined, а исключение не выбрасывается. Это исторически и спецификационно закреплённое поведение, чтобы можно было проверять наличие глобальных переменных (например, API окружения) без риска падения программы.

// Необъявленная переменная (не существует нигде)
typeof notDeclared;           // "undefined"

// То же самое, но обычное чтение значения:
notDeclared;                  // ReferenceError: notDeclared is not defined

Важное отличие: "необъявлена" и "в TDZ"

Термины часто путаются, но ситуации разные:

  • Необъявленная переменная: идентификатор вообще не был объявлен через var, let, const, function, class, import в доступных областях видимости
  • Объявленная, но недоступная из-за TDZ (temporal dead zone): переменная объявлена через let/const/class, но обращение происходит до выполнения строки инициализации

Для TDZ исключение из правила typeof не применяется: при обращении к переменной в TDZ будет выброшен ReferenceError, даже если используется typeof.

// Пример TDZ
{
  // Переменная объявлена ниже, но сейчас она в TDZ
  typeof tdzVar;              // ReferenceError: Cannot access 'tdzVar' before initialization
  let tdzVar = 1;
}
Если планируется "безопасная проверка существования" через typeof, важно, чтобы проверяемое имя не было объявлено как let/const в той же области ниже по коду, иначе возможен ReferenceError из-за TDZ.

Как работает typeof на практике

typeof всегда возвращает строку. Самые типичные результаты:

typeof undefined;             // "undefined"
typeof null;                  // "object"        // историческая особенность языка
typeof 123;                   // "number"
typeof 10n;                   // "bigint"
typeof "txt";                 // "string"
typeof true;                  // "boolean"
typeof Symbol("s");           // "symbol"
typeof function(){};          // "function"
typeof {};                    // "object"

Отсюда видно, почему вариант “вернётся null” неверен: typeof не возвращает null ни в каком случае; он возвращает только строку.

Разбор вариантов из задания

  • Будет выброшен ReferenceError, потому что переменная не объявлена — неверно для typeof и необъявленной переменной; верно для обычного чтения значения x
  • Вернётся строка undefined и ошибки не будет — верно (для действительно необъявленной переменной)
  • Вернётся null, так как переменная отсутствует — неверно, typeof возвращает строку, а не null
  • Вернётся строка not defined — неверно; такой строки typeof не возвращает (сообщение об ошибке is not defined относится к ReferenceError при обычном доступе)

Таблица: что будет в разных случаях

СитуацияПримерРезультат
Имя не объявлено нигдеtypeof noSuchName"undefined"
Обычное чтение несуществующего имениnoSuchNameReferenceError
var объявлена, но ещё undefinedvar a; typeof a"undefined"
let/const в TDZ{ typeof b; let b = 1; }ReferenceError
Объект и отсутствующее свойствоtypeof obj.missing"undefined" (если obj определён)
Сам объект не определёнtypeof obj.missingReferenceError (потому что сначала нужно прочитать obj)
Проверка typeof obj.missing безопасна только при гарантированно существующем obj. Если obj не объявлен, ошибка возникнет ещё до доступа к свойству.

Наглядная схема рассуждения

Шаг 1: Это typeof Identifier?
  ├─ Да → Шаг 2
  └─ Нет → обычные правила вычисления выражений

Шаг 2: Идентификатор существует в области видимости?
  ├─ Нет (unresolvable) → результат "undefined", без ошибки
  └─ Да → Шаг 3

Шаг 3: Идентификатор в TDZ?
  ├─ Да → ReferenceError
  └─ Нет → вернуть строку типа значения

Итого: при typeof на действительно необъявленной переменной возвращается строка undefined без ошибки; ReferenceError появляется при обычном обращении к имени или при typeof к переменной в TDZ.