Переменная есть, а её как будто нет? Разбираемся с проверками в JavaScript
Вы когда-нибудь писали скрипт, запускали его, и вдруг — бабах! — консоль браузера окрашивается в красный с криком Uncaught ReferenceError: myVar is not defined? Знакомо. Или наоборот: переменная объявлена, но вы не уверены, присвоено ли ей значение. В JavaScript эти два понятия («существует» и «инициализирована») часто путают даже опытные разработчики.
В этом руководстве мы раз и навсегда разберем, как правильно проверить, существует ли переменная в JavaScript, чем отличается «определена» от «инициализирована», и как избежать 90% ошибок, связанных с undefined и ReferenceError. Поехали!
Коротко о главном: что значит «переменная существует»?
В JavaScript у переменной есть три состояния:
- Не объявлена (undeclared) — переменной вообще нет в памяти. Попытка обратиться к ней выдаст
ReferenceError. - Объявлена, но не инициализирована (declared, but undefined) — мы написали
let x;илиvar y;, но не присвоили значение. Переменная существует, её тип —undefined. - Объявлена и инициализирована (declared and initialized) — у переменной есть конкретное значение (число, строка, объект и т.д.).
Большинство вопросов на Stack Overflow (а их там тысячи) сводятся к одному: «Как понять, что переменная не вызовет ошибку при обращении?» Ответ — используйте typeof. Но есть нюансы. Давайте разбираться.
Способ №1. Оператор typeof — ваш главный друг
Самый надёжный и безопасный способ проверить, определена ли переменная в JavaScript — это оператор typeof. Его главное преимущество: он никогда не выбрасывает ошибку, даже если переменная не объявлена.
Пример для необъявленной переменной
// Переменная myVar не объявлена
if (typeof myVar !== 'undefined') {
console.log('Переменная существует!');
} else {
console.log('Переменная НЕ существует или её значение undefined');
}
// Вывод: "Переменная НЕ существует или её значение undefined"
Обратите внимание: typeof возвращает строку 'undefined' как для необъявленной переменной, так и для объявленной, но не инициализированной (let x;). Это и хорошо, и плохо. Хорошо — потому что мы не ловим ошибку. Плохо — потому что мы не различаем два этих случая.
Пример для объявленной, но пустой переменной
let myVar; // объявлена, но не инициализирована
console.log(typeof myVar); // "undefined" — тоже undefined!
if (typeof myVar !== 'undefined') {
console.log('Переменная существует и имеет значение');
} else {
console.log('Переменная undefined (либо не объявлена, либо не инициализирована)');
}
Вывод: typeof — идеальное решение, если вам нужно просто избежать ReferenceError. Если же нужно отличить «не объявлена» от «пустая» — читайте дальше.
Способ №2. Проверка через window (глобальный контекст)
Если вы работаете в браузере и переменная объявлена глобально (через var или неявно), она становится свойством объекта window. Это открывает дополнительные возможности для проверки существования переменной.
Используем оператор in
// Глобальная переменная
var globalVar = 42;
console.log('globalVar' in window); // true
console.log('nonExistentVar' in window); // false
Этот метод работает только для глобальных переменных, объявленных через var или присвоенных без ключевого слова. let и const не создают свойств объекта window (они живут в блочной области видимости).
Используем hasOwnProperty
var anotherVar = 'hello';
console.log(window.hasOwnProperty('anotherVar')); // true
console.log(window.hasOwnProperty('fakeVar')); // false
Этот способ точнее, чем in, так как не проверяет унаследованные свойства прототипа.
Минус: работает только для глобального скоупа. Для локальных переменных внутри функций — не подходит.
Способ №3. Блок try...catch для самых отчаянных
Иногда нужно точно знать, что переменная не объявлена, а не просто равна undefined. Например, вы ждете, что переменная придет из внешнего скрипта, но её может не быть. В этом случае можно поймать ошибку:
let variableExists = true;
try {
// Пытаемся обратиться к переменной
console.log(potentiallyMissingVar);
} catch (e) {
if (e instanceof ReferenceError) {
variableExists = false;
console.log('Переменная не объявлена!');
} else {
// Другая ошибка — пробрасываем дальше
throw e;
}
}
console.log('Существует?', variableExists); // false
Этот метод редко используют на практике (слишком громоздко), но он даёт 100% точность. Применяйте его, когда typeof не даёт нужной детализации, а код критически важен.
Способ №4. Проверка инициализации (не путать с существованием!)
Очень частая ситуация: переменная объявлена, но вы не уверены, присвоено ли ей значение. Например, функция принимает опциональный параметр:
function greet(name) {
// Проверяем, инициализирована ли переменная name
if (name === undefined) {
console.log('Привет, незнакомец!');
} else {
console.log('Привет, ' + name + '!');
}
}
greet(); // "Привет, незнакомец!"
greet('Анна'); // "Привет, Анна!"
Но есть нюанс: что, если кто-то передаст undefined явно? greet(undefined) тоже выведет «незнакомец». Чтобы отличить «не передали» от «передали undefined», используйте arguments.length или проверку на null.
Более надёжная проверка инициализации
function configure(options) {
// Проверяем, что options — это объект и у него есть свойство theme
if (options && options.theme) {
console.log('Тема: ' + options.theme);
} else {
console.log('Тема не задана, используем стандартную');
}
}
configure({ theme: 'dark' }); // "Тема: dark"
configure({}); // "Тема не задана, используем стандартную"
configure(); // "Тема не задана, используем стандартную" (без ошибки!)
Обратите внимание на options && options.theme. Если options — undefined или null, JavaScript не пойдёт проверять options.the