JavaScript: ошибка Uncaught ReferenceError - переменная не определена
Uncaught ReferenceError: userName is not defined появляется, когда JavaScript пытается обратиться к переменной userName, но не может найти такое имя в текущей области видимости.
Например:
//js
console.log(userName);Если доступного объявления userName нет, выполнение останавливается с ReferenceError.
На практике причина может быть чуть менее очевидной. Переменная действительно может отсутствовать, но также она может находиться внутри другой функции или блока, использоваться до объявления, быть недоступной из другого модуля или вообще не попасть в страницу из-за проблемы с подключением JavaScript.
При этом ReferenceError не означает, что переменная существует, но содержит пустое значение. Если написать:
//js
let userName;
console.log(userName);ошибки не будет - результатом станет undefined. В первом случае JavaScript не знает такого идентификатора, во втором знает переменную, но её значение ещё не задано.
Переменной действительно может не быть
Самый простой вариант выглядит так:
//js
console.log(userName);В коде нет объявления userName, поэтому движок не может его найти.
Добавляем объявление:
//js
const userName = 'Alex';
console.log(userName);Теперь переменная существует в этой области видимости и выражение выполняется нормально.
Иногда причина оказывается ещё проще - опечатка:
//js
const username = 'Alex';
console.log(userName);username и userName для JavaScript - разные идентификаторы. Регистр букв тоже имеет значение.
Объявление есть, но переменная недоступна
Наличие переменной в файле ещё не означает, что к ней можно обратиться из любого места.
Например:
//js
function showUser() {
const userName = 'Alex';
console.log(userName);
}
showUser();
console.log(userName);Первый console.log() работает, а второй вызывает ReferenceError. userName создана внутри функции и снаружи этой функции не существует.
То же самое происходит с блочной областью видимости:
//js
if (true) {
let message = 'Hello';
console.log(message);
}
console.log(message);let и const ограничены блоком, в котором объявлены.
Из-за этого при поиске ошибки стоит смотреть не только на строку с ReferenceError, но и на место, где объявляется переменная. Иногда она находится буквально в нескольких строках выше, но внутри другого { ... }.
let и const нельзя использовать раньше объявления
Есть отдельный случай, который выглядит похожим:
//js
console.log(userName);
const userName = 'Alex';Здесь userName объявлена в том же блоке, но обратиться к ней до выполнения объявления нельзя. JavaScript выдаст ReferenceError.
Это связано с так называемой temporal dead zone - временной зоной до инициализации переменной.
С var поведение другое:
//js
console.log(userName);
var userName = 'Alex';Здесь ошибки ReferenceError не будет. До присваивания переменная имеет значение undefined.
Это одна из причин, почему старый код с var иногда ведёт себя совсем не так, как код на let и const. Для нового кода обычно используют let или const, а проблему с порядком выполнения исправляют в самом коде, а не заменой объявления на var.
Иногда виновата загрузка JavaScript
Предположим, переменная создаётся в одном файле:
//js
// config.js
const apiUrl = '/api';а используется в другом:
//js
// app.js
console.log(apiUrl);Если config.js не загрузился или выполняется не в том контексте, где ожидается, app.js может получить ReferenceError.
При обычном подключении скриптов имеет значение их порядок:
//html
<script src="config.js"></script>
<script src="app.js"></script>Если поменять их местами, app.js может выполниться раньше объявления.
При такой ошибке стоит открыть DevTools и посмотреть вкладки Console и Network. В первой будет сама ошибка, а во второй можно проверить, загрузился ли нужный JavaScript-файл и не вернулся ли, например, ответ 404.
В модулях переменная не становится глобальной
С современным JavaScript есть ещё одна распространённая ситуация. Файл с type="module" имеет собственную область модулей.
Например:
//js
// user.js
const userName = 'Alex';И в другом модуле:
//js
// app.js
console.log(userName);Само наличие userName в user.js не делает её доступной в app.js.
Для этого используется экспорт и импорт:
//js
// user.js
export const userName = 'Alex';//js
// app.js
import { userName } from './user.js';
console.log(userName);Похожая ситуация постоянно встречается в проектах на Vite, React и других современных сборщиках. Если переменная находится в другом модуле, сначала стоит проверить export и import, а уже потом искать ошибку в самом имени.
typeof может проверить отсутствующий идентификатор
Для необъявленной переменной есть необычное исключение:
//js
console.log(typeof userName);Если userName вообще нигде не объявлена, результатом будет:
//text
undefinedСам по себе такой вызов ReferenceError не вызывает.
Это иногда используют при проверке существования глобального объекта:
//js
if (typeof someLibrary !== 'undefined') {
someLibrary.start();
}
Но с let и const есть нюанс: если переменная объявлена в текущей области видимости, но находится в temporal dead zone, typeof не спасает:
//js
console.log(typeof userName);
const userName = 'Alex';Здесь всё равно возникнет ReferenceError.
Не путайте переменную со свойством объекта
Эти две ситуации выглядят похоже, но JavaScript обрабатывает их по-разному.
//js
const user = {};
console.log(user.name);Результат:
//text
undefinedСвойства name у объекта нет, но сам объект user существует.
А здесь:
//js
console.log(userName);JavaScript пытается найти отдельную переменную userName. Если её нет, возникает ReferenceError.
Такая разница особенно заметна при работе с ответами API:
//js
const response = {
user: {
name: 'Alex'
}
};
console.log(response.user.name);Если ошибиться и написать:
//js
console.log(response.username);получим undefined.
Если же написать:
//js
console.log(username);будет уже ReferenceError, потому что username - отдельный идентификатор, которого в коде нет.
Иногда исправлять нужно сам способ передачи данных
Бывает, что ошибка появляется из-за попытки использовать переменную слишком далеко от места, где она создаётся.
Например:
//js
function createUser() {
const userName = 'Alex';
}
function printUser() {
console.log(userName);
}Создание переменной внутри createUser() не делает её доступной для printUser().
Вместо попытки сделать всё глобальным лучше передать значение явно:
//js
function createUser() {
return 'Alex';
}
function printUser(userName) {
console.log(userName);
}
const userName = createUser();
printUser(userName);
Так зависимости функции становятся видны прямо в её параметрах. В больших проектах это обычно значительно упрощает поиск подобных ошибок.
Как быстро найти причину
Если в консоли появилась строка вроде:
//text
Uncaught ReferenceError: userName is not definedсначала найдите точную строку, на которой остановилось выполнение.
После этого достаточно проверить несколько вещей:
действительно ли существует объявление
userName;совпадает ли регистр букв;
находится ли переменная в той же области видимости;
не используется ли
letилиconstдо объявления;не находится ли нужная переменная в другом модуле;
правильно ли выполнен
import;загрузился ли JavaScript-файл;
не перепутано ли имя переменной со свойством объекта.
В браузере особенно полезно перейти по ссылке на файл и номер строки из Console. Если ошибка пришла из собранного JavaScript, DevTools при наличии source map обычно позволяет увидеть исходный файл.
ReferenceError в итоге сводится к довольно конкретной вещи: JavaScript не смог разрешить имя, к которому произошло обращение. Дальше нужно выяснить почему - идентификатор отсутствует, находится за пределами текущей области видимости, используется слишком рано или не был импортирован.
А undefined - уже другая ситуация: переменная найдена, просто её значение в данный момент не задано.
Комментарии
Чтобы оставить комментарий, войдите в аккаунт.